Rewrite Rule Only Works With R Flag - .htaccess

I am stuck trying to work out why my rewrite rules will not work as internals, I do not want to change the url in the browser but if I remove the R I get an error.
The rewrites are to tidy up the get variables for 3 modules that I have written for joomla. Obviously I want the clean urls to stay in the browser and i have written the php to generate the links in this sef format. So I really need this rewrite to be internal and invisible to the end user.
From .htaccess
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ /$1/ [L,R=301]
#Example /hire/audio/speakers/all
RewriteRule ^hire/([0-9a-zA-Z-&]+)/([0-9a-zA-Z-&]+)/all /section?section=$1&sub_section=$2&filter=1 [NC,L,R]
#Example /hire/audio/speakers/1
RewriteRule ^hire/([0-9a-zA-Z-&]+)/([0-9a-zA-Z-&]+)/(\d+) /section?section=$1&sub_section=$2&filter=$3 [NC,L,R]
#Example /hire/audio/speakers/jbl-jrx112m
RewriteRule ^hire/([0-9a-zA-Z-&]+)/([0-9a-zA-Z-&]+)/([0-9a-zA-Z-&]+) /detail?section=$1&sub_section=$2&product=$3 [NC,L,R]
#Example /hire/audio/speakers
RewriteRule ^hire/([0-9a-zA-Z-&]+)/([0-9a-zA-Z-&]+) /section?section=$1&sub_section=$2 [NC,L,R]
#Example /hire/audio
RewriteRule ^hire/([0-9a-zA-Z-&]+) /hire?section=$1 [NC,L,R]
Also is there any way to ensure that '&' is rewritten as %26 in the rewrite for the variable string data only leaving the & for the get variables in the url untouched? Eg:
/hire/audio/speakers/d&b-q7 = /detail?section=audio&sub_section=speakers&product=d%26b-q7
Any help would be appreciated, thanks.

Related

Implementing "friendly" URLs using .htaccess

I tried some of the other answers I could find in here, but it didn't work out. It's really simple though.
I want
/page?id=PAGENAME
to be accessible AND redirected to
/PAGENAME
Can you help me?
EDIT:
It feels like my already messed-up .htaccess file needs to be included in here. I already have basic rewriting enabled, but this feature is needed for two other "special pages". In the requested solution above, I would therefore just replace "page" with the two pagenames (it's danish names, so I thought it was easier this way).
Currently I have this. If you have any improvements to it, it's appreciated - but I just want this to work with the requested solution aswell.
# Options -Multiviews -Indexes +FollowSymLinks
RewriteEngine On
RewriteBase /
# Always on https
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
# remove trailing slash
#RewriteRule ^(.*)\/(\?.*)?$ $1$2 [R=301,L]
#301 Redirect everything .php to non php
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([^.]+\.)+php?\ HTTP
RewriteRule (.+)\.php?$ http://MYURL.dk/$1 [R=301,L]
#Hide the .php from url
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php
#301 Redirect everything mistype after file extension -
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
#301 Redirect everything to current url -
RedirectMatch permanent /(.*).php/.* http://MYURL.dk/$1.php
RewriteCond %{REQUEST_FILENAME} -D
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ $1/ [L]
#301 Redirect from non www to www
RewriteCond %{HTTP_HOST} ^www.MYURL.dk [NC]
RewriteRule (.*) http://MYURL.dk/$1 [R=301,L]
#301 redirect index.php to /
RewriteBase /
RewriteCond %{REQUEST_URI} index.php
RewriteRule .* http://MYURL.dk/ [R=301,L]
#Deny access to songs
RewriteCond $1 !(loadmedia)\.php
RewriteRule ^songs/(.*)$ - [L,F]
Generally the URL in address bar should be like
www.siteurl.com/pagename/ for seo purpose and then read this url from .htaccess using rule which gives this query string parameter values in your php file.
.htaccess rule can be like
RewriteRule ^(.*)/$ /page?id=$1 [QSA,L]
It looks like you are wanting to implement "friendly" (or "pretty") URLs, making the URLs more friendly for you users (search engines don't really mind what your URLs look like).
The first step is to change all your on-page links to use the new "friendly" URL. So, you links should all be of the form /pagename (not /page?id=PAGENAME).
Then, in .htaccess, you need to internally rewrite this "friendly" URL into the real URL that your server understands. This can be done using mod_rewrite. In the .htaccess file in your document root:
# Enable the rewrite engine
Options +FollowSymLinks
RewriteEngine On
# Rewrite the "friendly" URL back to the real URL
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{QUERY_STRING} !^id=
RewriteRule ^([\w-]*) /page?id=$1 [L]
If the file does not exist (!-f) and does not contain the id URL param then internally rewrite the request from /<pagename> to /page?id=<pagename>. This assumes your <pagename> consists only of the characters a-z, A-Z, 0-9, _ and -.
If this is a new site and the old URLs are not already indexed or referenced by external sites then you can stop here.
However, if you are changing an existing URL structure then you also need to externally redirect the real (ugly) URL to the "friendly" URL before the above internal rewrite. (This is actually what you are asking in your question.) In order to prevent a rewrite loop we can check against %{THE_REQUEST} (which does not change when the URL is rewritten).
# Redirect real URLs to "friendly" URLs
RewriteCond %{THE_REQUEST} \?id=([\w-]*)
RewriteRule ^page$ /%1? [R=302,L]
Change the 302 (temporary) to 301 (permanent) when you are sure this is working OK. Permanent redirects are cached by the browser so can make testing a problem.
So, in summary, with the above two parts shown together:
# Enable the rewrite engine
Options +FollowSymLinks
RewriteEngine On
# Redirect real URLs to "friendly" URLs
RewriteCond %{THE_REQUEST} \?id=([\w-]*)
RewriteRule ^page$ /%1? [R=302,L]
# Rewrite the "friendly" URL back to the real URL
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{QUERY_STRING} !^id=
RewriteRule ([\w-]*) /page?id=$1 [L]
The order of directives is important. External redirects should nearly always come before internal rewrites.
UPDATE#1:
I want /concept?id=NAME to go to /NAME and /studio?id=NAME to go to /NAME - there's 5-10 different "pages" from both concept and studio. [Corrected according to later comment]
Since id=NAME maps to /NAME you can achieve all 10-20 redirects with just a single rule:
RewriteCond %{QUERY_STRING} ^id=(NAME|foo|bar|baz|abc|def|ghi)
RewriteRule ^(concept|studio)$ /%1? [R,L]
This will redirect a URL such as /studio?id=foo to /foo.
As with all external redirects this should be one of the first rules in your .htaccess file.
Change R to R=301 when you have tested that it is working OK.
To make this more "dynamic", ie. match any "NAME" then change the CondPattern, for example:
RewriteCond %{QUERY_STRING} ^id=([\w-]*)
UPDATE#2:
If the path part of the URL (ie. concept or studio) is required then you can modify the RewriteRule substitution like so:
RewriteCond %{QUERY_STRING} ^id=([\w-]*)
RewriteRule ^(concept|studio)$ /$1/%1? [R,L]
Which will redirect /concept?id=foo to /concept/foo.
Or, to be completely "dynamic" (bearing in mind this will now capture anything):
RewriteCond %{QUERY_STRING} ^id=([\w-]*)
RewriteRule ^([\w-]+)$ /$1/%1? [R,L]

mode rewrite for m.example.com/subfolder/index.php?user=xxx

I am a new bee and I want to redirect following URL
m.site.com/subfolder/index.php?user=xxx
to a search engine frendly url like below using .htacess mode rewrite
m.site.com/subfolder/xxx
please explain me the correct way
You can use in the .htaccess file, in the subfolder (It is important):
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{QUERY_STRING} ^user=(.+)$
RewriteRule ^ %1? [R=302,L]
RewriteRule ^(.*)$ index.php?user=$1 [L]
Change R=302 for R=301 when test work well.

Htaccess - Rewrite engine (reverse engineering a line of code)

On a site I'm working on, if you enter the url, plus 1 directory, the htaccess adds a trailing slash.
So, this: http://www.mysite.com/shirts
Becomes this: http://www.mysite.com/shirts/
The htaccess that runs the site is quite long and complex, so it's not easy to find or test which rule is causing the rewrite. I was able to track down the issue to this line of code (I think):
RewriteRule (.*) http://www.mysite.com/$1 [R=301,L]
Does this rule match the behavior I'm describing above? It seems to be the cause, but it doesn't make logical sense to me. I don't unsderstand where the trailing slash is coming from.
Can someone shed some light on this for me? Thanks in advance.
Edit: MORE:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^mysite\.com$
RewriteRule (.*) http://www.mysite.com/$1 [R=301,L]
By default apache will add the ending /, you will have to use:
DirectorySlash Off
To disable that behavior which is caused by mod_dir, you can read more about it here.
However if you're trying to remove the / to fix images not showing. That is not the right way to do it, you should instead use the HTML base tag, for example:
<BASE href="http://www.yourdomain.com/">
Read more here about it.
Your current rule as you have updated on your question:
RewriteCond %{HTTP_HOST} ^mysite\.com$
RewriteRule (.*) http://www.mysite.com/$1 [R=301,L]
Means:
if domain on the URL is only mysite.com
redirect current URL to domain with www.
So an example of it would be, if you access:
http://domain.com/blog/some_blog_article
It will redirect the user to:
http://www.domain.com/blog/some_blog_article
Note how it retains everything and only add the www. to the domain.
If you really want to redirect it regardless here is one way to do it:
Options +FollowSymLinks -MultiViews
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^mysite\.com$ [NC]
RewriteRule (.*) http://www.mysite.com/$1 [R=301,L]
# check if it is a directory
RewriteCond %{REQUEST_FILENAME} -d
# check if the ending `/` is missing and redirect with slash
RewriteRule ^(.*[^/])$ /$1/ [R=301,L]
# if file or directory does not exist
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
# and we still want to append the `/` at the end
RewriteRule ^(.*[^/])$ /$1/ [R=301,L]

htaccess rewrite rule, old URL to new

A bit of help fellow SO people.
What I have at the moment (based on some code I used for a different type of URL).
I want the first URL to redirect to the second, with no query string included afterwards
This is what I have to so far.
RewriteRule ^(page.php?id=missionstatement+)/?$ http://example.com/why/mission-statement [R=301,L]
RewriteRule ^(page.php?id=ofsted+)/?$ http://example.com/how/ofsted-report [R=301,L]
RewriteRule ^(page.php?id=governingbody+)/?$ http://example.com/governors [R=301,L]
Here is the rule (will redirect 1 URL):
RewriteCond %{QUERY_STRING} ^id=whatever
RewriteRule ^page\.php$ http://%{HTTP_HOST}/how/somehow? [R=301,L]
This rule intended to be placed in .htaccess in website root folder. If placed elsewhere some small tweaking may be required.
I have used %{HTTP_HOST} -- this will redirect to the same domain as requested URL. If domain name has to be different, replace it by exact domain name.
The ? at the end of new URL will get rid of existing query string.
Ahoy!
Give this a whirl:
#check mod_rewrite is enabled
<IfModule mod_rewrite.c>
#enable mod rewrite
RewriteEngine On
#set working directory
RewriteBase /
#force trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ $1/ [R=301,L]
#bootstrap index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^page.php\?id=(.*)$ http://www.willans.com/page.php/$1 [R=310,L]
#end mod rewrite check
</IfModule>
It's been a while since i've done any web dev, but that should be a push in the right direction at least ;)

htaccess 301 redirection using regular expression

This is my current .htaccess file
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ $1/
RewriteRule ^([^/]+)/$ index.php?p1=$1 [L]
RewriteRule ^([^/]+)/([^/]+)/$ index.php?p1=$1&p2=$2 [L]
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/$ index.php?p1=$1&p2=$2&p3=$3 [L]
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/([^/]+)/$ index.php?p1=$1&p2=$2&p3=$3&p4=$4 [L]
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/$ index.php?p1=$1&p2=$2&p3=$3&p4=$4&p5=$5 [L]
Basically, it takes up to five "Friendly url folders" and assign the value to varibles and then, send those to my index.php page
IE: http://www.example.com/ford/focus/grey/
$p1 = 'ford';
$p2 = 'focus';
$p3 = 'grey';
$p3 = 'grey';
So far, so good.
Now, I need to integrate a 301 instruction (RegExp?) in that same .htaccess because initially, I had GET parameters like this :
IE: http://www.example.com/ford/focus/grey/?lang=fr
I need to get rid of all GET variables because Google sees it as duplicate content (even if I'm using the nofollow attribute on my languages links)
IE: http://i.want.to.keep/my/url/?AND_DUMP_GET_VARIABLES
http://www.example.com/ford/focus/grey/?lang=fr
http://www.example.com/ford/focus/grey/?lang=en
http://www.example.com/ford/focus/grey/?lang=sp
==> http://www.example.com/ford/focus/grey/
Logically, the instruction should be interpreted between the first and the second block but I just don't know where to start. Any hints?
THANKS!
As I understand you want to get rid of the QUERY STRING and redirect (301 Permanent Redirect) to the same URL but without QUERY STRING.
The rule below will redirect EVERY request that has query string:
RewriteCond %{QUERY_STRING} !^$
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1? [R=301,L]
1. The ? will do the magic -- will strip query string
2. You desperately need this line: RewriteCond %{ENV:REDIRECT_STATUS} ^$. The problem is that it may not work on your Apache setup and I cannot give you what exactly you need to make it work (it works fine on my vanilla Apache v2.2.17 on Windows).
After rewrite (internal redirect) occurred, it goes to next iteration and Apache starts matching all rules from the top again but for already rewritten URL. If we not add the above line, then mod_rewrite will apply the above rule to rewritten URL form and you will end up with all URLs get rewritten to /index.php with no parameters at all.
If the above will not work, then try the code below:
# do not do anything for already existing files and folders
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .+ - [L]
RewriteCond %{QUERY_STRING} !^$
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1? [R=301,L]
With help of # do not do anything for already existing files and folders rule, mod_rewrite will stop rewriting after URL will be rewritten to /index.php?p1=... format.
In case the above will not work at all (better -- in addition to the above -- I would suggest adding this anyway) use <link rel="canonical" href="FULL_PROPER_RUL"/> in your page:
http://googlewebmastercentral.blogspot.com/2009/02/specify-your-canonical.html
http://www.google.com/support/webmasters/bin/answer.py?answer=139394

Resources