.htaccess rewrite rule confusion/conflicts - .htaccess

I have the below rewrite rules setup on a site. I' trying to set it up so I have the below different URLs.
Current .htaccess
Options +FollowSymlinks
RewriteEngine On
RewriteBase /
RewriteRule ^([^-]*)/$ ?action=$1 [L]
RewriteRule ^([^-]*)-([^-]*)/$ ?action=$1&id=$2 [L]
Required URLs
www.site.com
www.site.com/page/
www.site.com/product-1234/
www.site.com/privacy-policy/
The problem is that the second rewrite rule is affecting the privacy-polcy url but it shouldn't as the second rewrite rule is specific only to the product pages that have the product ID in it.
I'm also trying to ignore directories that exist as the structure of my site so under root I have the below directories which I don't want the rewrite rules to affect as the user shouldn't know anything about these directories.
/system/
/tasks/

# catch more specific urls:
RewriteRule ^product-([0-9]*)/$ ?action=product&id=$1 [L]
# ignore requests that want files or directories that do exist:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# then continue with the less specific:
RewriteRule ^([^/]*)/$ ?action=$1 [L]

Related

Rewrite folders with .htaccess

For a website, I want to set up a redirection using .htaccess.
My folder structure is something like
/
/folderA/
/folderB/
/index/
where folderA and B and index contain subfolders and files. Now, I want to rewrite all requests for the root / and for all not existing folders and files to index. It should be masked. It seems to me like an easy task but I cannot get it to work. So far, I tried
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) /index/$1 [L]
The redirection somehow works but it does not work when I call the root http://example.org/ directly.
Is the root also seen as valid directory or excluded in the RewriteCond checks? Any ideas how to realize that?
Yes, the root is also a directory. You will need to add another rule to rewrite the root only. For example:
RewriteRule ^$ /index/ [L]
And since the root is a directory, you might as well exclude this from the first rule. ie. Change (.*) to (.+).
HOWEVER, your existing rule will result in a rewrite-loop (500 error) if the URL you are rewriting to in /index/... does not exist either*1. eg. If you request /foo, it rewrites to /index/foo and if /index/foo does not exist then it rewrites to /index/index/foo to /index/index/index/foo etc.
You will need to add an additional condition (or use a negative lookahead) to prevent requests to /index/... itself being rewritten.
(*1 Unless you have another .htaccess file in the /index subdirectory that contains mod_rewrite directives and you have not enabled mod_rewrite inheritance.)
For example:
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/index/
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.+) /index/$1 [L]
RewriteRule ^$ /index/ [L]

.htaccess prevent of redirect if folder name in url

I have some folders in the root dir with an .htaccess file inside to deny for any access(deny from all). And my htaccess in root is:
RewriteEngine On
Options -Indexes
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
It's working fine except when I get the folders name in url. I want to ignore folders name and just redirect any url to index.php?url.
Could anyone help?
The !-d, !-f, !-l conditions mean only apply the rewrite rule if the access url does not resolve to an existing file, directory or link. So if the directory exists, it won't apply the rule. You need to remove those. You then need to prevent the recursive rewrite of index.php to itself like so :
RewriteRule ^index.php$ - [L]
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
You probably want to also change .+ in the last rule to .* to also match the empty url.
Indeed it seems the inner .htaccess files are parsed first, before the RewriteEngine one. So you will need to remove those .htaccess and rely on the rewrite rule.

.htaccess rules - How to redirect incoming "/login.php" url request to "index.php?do=login"?

I want to redirect all incoming url requests to index.php via .htaccess
Example:
/johngroup -> /index.php?do=johngroup
/addmem -> /index.php?do=addmem
/autoshare -> /index.php?do=autoshare
/spamwall -> /index.php?do=spamwall
index.php will handle all requests.
Following code is not working:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} ^/([A-Za-z0-9_-.]*).php? do=(.*)
RewriteRule .* /%1.php?do=%2 [R=301,L]
</IfModule>
This works for me:
RewriteEngine On
RewriteRule ^index.php - [L] # 1
RewriteRule ^(.*).php$ index.php?do=$1 [L] # 2
RewriteRule ^(\w+)$ index.php?do=$1 # 3
Explanation:
If urls starts with /index.php, stop processing. Otherwise proceed to next rule.
If url format is /x.php, rewrite to /index.php?do=x and stop processing further. Otherwise proceed to next rule.
Convert any url e.g /test, to /index.php?do=test.
You can also test and tweak htaccess rules using these sites:
Htaccess Tester
Rewrite Rule Tester
example.com/test.php to example.com/index.php?do=test
Try the following in your root .htaccess file:
RewriteEngine On
RewriteCond %{REQUEST_URI} !^index\.php$
RewriteRule ^(\w+)\.php$ index.php?do=$1 [L]
The above will internally rewrite /test.php to /index.php?do=test (ie. /test.php remains in the browsers address bar), regardless of whether test.php exists as a physical file on the filesystem. Basically, any file that has a .php file extension. The RewriteCond directive prevents a rewrite loop.
If you only need to rewrite URLs that would map to physical files, eg. test.php is a physical file on the filesystem then add an additional condition to check for the existence of this file before rewriting:
RewriteEngine On
RewriteCond %{REQUEST_URI} !^index\.php$
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(\w+)\.php$ index.php?do=$1 [L]

Root folder change (.htaccess)

In my "public_html" directory I have the following structure:
- root
- index.html
- blog
- index.html
- lab
- index.html
- wp
- (WORDPRESS FILES)
The "lab" and "wp" directories are just subdomain directories ("http://lab.tomblanchard.co.uk" and "http://wp.tomblanchard.co.uk") which work fine.
Basically I want the main domain ("http://tomblanchard.co.uk") to point to the "root" directory without any actual redirecting, for example, I want "http://tomblanchard.co.uk" to point to the "index.html" file within the "root" directory, I want "http://tomblanchard.co.uk/blog" to point to the "index.html" file within the "root/blog" directory and so on.
I have kind of achieved this with the following code in my ".htaccess" file:
# Add directives
RewriteEngine on
# Remove ".html" extension from URLs
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html
# Change root directory to "root" folder
Options +FollowSymLinks
RewriteCond %{REQUEST_URI} !(.*)root
RewriteRule ^(.*)$ root/$1 [L]
The only problem is that things like "http://tomblanchard.co.uk/root/" and "http://tomblanchard.co.uk/root/blog/" still work when really they shouldn't even be able to be accessed (404).
If anyone has any idea on how to sort this or has a stronger method of doing this it would be greatly appreciated.
Update
Finally got it working how I wanted it after hours of researching, I used the following:
# Add directives
RewriteEngine on
# Change root directory to "root" folder
RewriteCond %{THE_REQUEST} ^GET\ /root/
RewriteRule ^root/(.*) /$1 [L,R=301]
RewriteRule !^root/ root%{REQUEST_URI} [L]
The order of directives in mod_rewrite is important, as each rule sees the output of the previous rule as its input to test. You need to do 3 (or possibly 4) things, in order:
Deny access to any URL beginning /root/ (we have to do this first, else everything will be denied!)
It's generally good practice to ensure each URL has only one valid form, so URLs which do specify .html should cause a browser redirect to the non-.html form. This needs to happen before other rewrites, otherwise you can't tell the difference between a .html from the browser and one you've added virtually.
Look up any URL not denied above in the /root/ directory, rather than the configured DocumentRoot
Look up any URL not pointing at a directory under the URL + .html, if that file exists. This has to come after other rewrites, or the "file exists" check will always fail.
# General directives
Options +FollowSymLinks
RewriteEngine on
# Deny URLs beginning /root/, faking them as a 404 Not Found
RewriteRule ^root/ [R=404]
# Additional rule to strip .html off URLs in the browser
RewriteRule ^(.*)\.html$ $1 [R=permanent,L]
# Rewrite everything remaining to the /root sub-directory
# (Host condition was in your post originally, then edited out; this is where it would go)
RewriteCond %{HTTP_HOST} ^(www\.)?tomblanchard\.co\.uk$
RewriteRule ^(.*)$ root/$1
# Handle "missing" ".html" extension from URLs
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html
PS: Note my careful language to describe (internal) rewrites, as opposed to (browser) redirects: the rule you have is not removing .html from anything, it is adding it, thus allowing the page to be accessed if someone else removes it. Since you are often modifying both within a set of rules, it's important to keep clear in your head the distinction between the URL the browser has requested, and the virtual URL Apache will ultimately serve.
You are not defining any rule to block /root address so how do you want to block it when there is nothing to do that?
Try this:
# Add directives
RewriteEngine on
RewriteCond %{REQUEST_URI} .root [NC]
RewriteRule (.*) / [L,R=404]
# Remove ".html" extension from URLs
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html
# Change root directory to "root" folder
RewriteCond %{HTTP_HOST} ^tomblanchard.co.uk$ [NC,OR]
RewriteCond %{HTTP_HOST} ^www.tomblanchard.co.uk$
RewriteCond %{REQUEST_URI} !.root
RewriteRule (.*) /root/$1 [L,R=301,QSA]
This is not tested so if it wouldn't work, play around with it to get your need.

htaccess rewrite for subdomain only

I'm trying to rewrite some parameters to beautiful links, but for a subdomain / a folder only. Unfortunately I can't get it to work, maybe also because there are some other rewrites in line before...
Heres my code:
<IfModule mod_rewrite.c>
# NON-WWW TO WWW
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example.com
RewriteRule (.*) http://www.example.com/$1 [R=301,L]
# WORDPRESS-BLOG
Options +FollowSymlinks
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# REDIRECT FOR SUBDOMAIN
RewriteCond %{HTTP_HOST} ^subdomain.example.com
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/.]+)(?:/)?$ index.php?cshort=$1 [L]
RewriteRule ^([^/.]+)/([^/.]+)(?:/)?$ /index.php?cshort=$1&cid=$2 [L]
RewriteRule ^([^/.]+)/([^/.]+)/([^/.]+)(?:/.*)?$ /index.php?cshort=$1&cid=$2&step=$3 [L]
</IfModule>
Basically only the last part is the one I want to rewrite to change URLs from something like
http://subdomain.example.com/index.php?cshort=abc&cid=123&step=1 to http://subdomain.example.com/abc/123/1
The other rewriting rules for www.example.com shouldn't get affected. Unfortunately my current codes only does the first two rules for the blog and the www, but nothing happens on the subdomain. What's wrong in my code?
When you say that you want to rewrite from http://subdomain.example.com/index.php?cshort=abc&cid=123&step=1 to http://subdomain.example.com/abc/123/1 you mean that you want the user to enter the pretty URL and to have it serve the full URL in the background, not that you want to redirect from the ugly to the pretty URL, right?
In your RewriteRules, what are you trying to accomplish with "(?:/)?"? As written, that doesn't make any sense to me. If you're just trying to match whether or not the directory path ends with a slash, you can do that as follows:
RewriteRule ^([^/.]+)/?$ index.php?cshort=$1 [L]
EDIT: Additional suggestions:
Move the "Redirect for subdomain" section above the "Wordpress Blog" section. Since the Wordpress rule applies to "everything that's not a real file or directory, regardless of domain" that should go last.
RewriteConds only apply to a single RewriteRule that follows them. For each of the three rules you have listed under "Redirect for subdomain", after updating them per the above suggestion, you need to repeat the two RewriteCond lines in front of the RewriteRule.

Resources