I am attempting to pretty my URLs using an .htaccess file. I've tried a few different rules but the site keeps crashing. I've included the code that adds the public folder to the root directory as, even though it works, I suspect it might be effecting the latter code, which doesn't work.
# Turn Rewrite Engine On
RewriteEngine on
# Make /public/ part of root
RewriteCond %{HTTP_HOST} ^mysite.dev$ [NC,OR]
RewriteCond %{HTTP_HOST} ^mysite.dev$
RewriteCond %{REQUEST_URI} !public/
RewriteRule (.*) /public/$1 [L]
# Rewrite for terms-and-conditions.php
RewriteRule ^legal$ terms-and-conditions.php [NC,L]
# NC makes the rule non case sensitive
# L makes this the last rule that this specific condition will match
# $ in the regular expression makes the matching stop so that "legalblah" will not work
# Rewrite for package.php?feature=something
RewriteRule ^package/([0-9a-zA-Z]+)$ package.php?feature=$1 [NC,L]
Related
BEFORE I installed SSL things were working perfectly!! Here is the code I have in my root webserver .htaccess file:
Options +MultiViews
RewriteEngine On
RewriteCond %{HTTP_HOST} andrea\.com [NC]
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://andrea.com/$1 [R,L]
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule (.*) $1.php [L]
It works and it does exactly what I want it to do. So if I go to for example:
www.andrea.com/account
it accesses "www.andrea.com/account.php". Which is what I want.
I do however have a folder in root called "products". There is another ".htaccess" file in that folder and I don't know which of these 2 must be changed to make the following thing below work.
When you go to this url:
http:____/products/view/Hello/Goodbye
I want it to access "view.php" in the 'products' folder and in that php file I could do this:
$id = $_GET["id"]; // This would have "Hello"
$cat = $_GET["cat"]; // This would have "Goodbye"
And this works well when I use this htaccess in the "products" folder:
RewriteEngine on
RewriteCond %{HTTP_HOST} !^$
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTPS}s ^on(s)|
RewriteRule ^ http%1://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]*)/?(.*)$ /products/view.php?id=$1&cat=$2
The problem with this code above is, if I go to:
http:____/products/Hello/Goodbye
I want it to access the "index.php" that is in "products" folder. But instead it goes to "view.php" instead!! It's like the htaccess code above forced all to go to view.php (which should only be done if I have the "view/____" in the url.
I want the url above to go to "index.php" in the "products" folder and in that file I should be able to access ID and CAT variables.
Any ideas of what to change in my .htaccess file? Sorry I spent over 2 hours I don't understand a single line at the bottom of my code but it doesn't work :/
Options +MultiViews
First off, you should disable MultiViews. In my answer to your earlier question, my suggestion to use MultiViews was strictly an "alternative" method in the context of your question. You cannot use both methods (mod_rewrite and MultiViews) to work with extensionless URLs. And since you are now wanting to do more things and pass parameters, MultiViews will only create conflicts. (MultiViews will likely "win" and no parameters get passed.)
Also, do you specifically need the additional .htaccess file in the /products subdirectory? It will be (arguably) easier to have a single .htaccess file in the document root. This will avoid having to repeat the HTTP to HTTPS redirect (although you've not actually included an HTTP to HTTPS redirect in the subdirectory .htaccess file?).
# /products/.htaccess
RewriteRule ^([^/]*)/?(.*)$ /products/view.php?id=$1&cat=$2
This directive matches both view/Hello/Goodbye and Hello/Goodbye, which explains why everything is being written to your view.php script. However, it's not actually doing what you say either - which is puzzling. If you request /products/view/Hello/Goodbye then it will rewrite the request to /products/view.php?id=view&cat=Hello/Goodbye - which is not the intention (unless MutliViews is enabled, in which case no parameters will be passed at all).
You need to actually check for views in the requested URL-path before attempting to rewrite to views.php. And if views is not present then rewrite to index.php instead. This "conditional branching" can be achieved by simply arranging the directives in the order of "more specific" rules first.
For example, in your root .htaccess file try the following. (And remove the /products/.htaccess file altogether.)
# Ensure that MultiViews is disabled
Options -MultiViews
RewriteEngine On
# HTTP to HTTPS canonical redirect
RewriteCond %{HTTP_HOST} example\.com [NC]
RewriteCond %{SERVER_PORT} 80
RewriteRule (.*) https://example.com/$1 [R=301,L]
# Abort early if the request already maps to (or looks like) a file or directory
RewriteCond %{REQUEST_URI} \.\w{2,4}$ [OR]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# 1. Rewrite "/products/view/<id>/<cat>" to "/products/view.php?id=<id>&cat=<cat>
RewriteRule ^(products/view)/([^/]*)/?(.*) $1.php?id=$2&cat=$3 [L]
# 2. Rewrite "/products/<id>/<cat>" to "/products/index.php?id=<id>&cat=<cat>
RewriteRule ^(products)/([^/]*)/?(.*) $1/index.php?id=$2&cat=$3 [L]
# 3. Extensionless URLs for other requests
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule (.*) $1.php [L]
The order of the 3 rules above is important. The most specific rule is first. Including the L flag to prevent further (unnecessary) processing.
Note that, as per your original directives, for a request of the form /products/view/Hello/Goodbye (or /products/Hello/Goodbye), the Hello/Goodbye part is entirely optional and will naturally result in the id and cat URL parameters being set, but empty.
Also, as per your original directives, a request of the form /products/view/Hello/Goodbye/foo/bar/baz will result in the cat URL parameter being set to Goodbye/foo/bar/baz (anything that follows the initial path segment).
You do not necessarily need to check that a request maps to a file or directory (which is relatively expensive) if you make your regex more specific and only match what you need to match. For example, your regex /([^/]*)/?(.*) currently match pretty much anything. But if your <id> and <cat> variables can only consist of lowercase letters (for example) then this could avoid the need for the filesystem checks.
Other notes:
Do you need to check the hostname in the HTTP to HTTPS redirect? Do you host multiple domains? Otherwise the condition that checks against the HTTP_HOST server variable is not required.
You can use the following rule to rewrite /products/Hello/Goodbye to /products/index.php .
RewriteRule ^Hello/GoodBye/?$ /product/index.php?id=hello&cat=Goodbye [L,NC]
Here is your complete /product/.htaccess .
RewriteEngine on
RewriteCond %{HTTP_HOST} !^$
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTPS}s ^on(s)|
RewriteRule ^ http%1://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
#rewrite /products/Hello/GoodBye to /products/index.php
RewriteRule ^Hello/GoodBye/?$ /products/index.php?id=Hello&cat=Goodbye [L,NC]
###################
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]*)/?(.*)$ /products/view.php?id=$1&cat=$2
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]
I am trying to apply mod rewrites to my URL to make it nicer but I am getting caught up in all the confusion of this subject.
Please could you help me out with the following examples of what I want to do :
I want to attach any variable from the root of my site into the lyprofile.php page
# Turn mod_rewrite on
RewriteEngine On
RewriteCond %{THE_REQUEST} /(.*)
RewriteRule /(.*) lyprofile.php?us=$1
I want a url such as profile/settings to go to lysettings.php
# Turn mod_rewrite on
RewriteEngine On
RewriteCond %{THE_REQUEST} /profile/settings
RewriteRule /profile/settings lysettings.php
These two examples if working should help me to work out all my other URL's, but I can't get these to work.
Also do you need an absolute URL, as I'm working on my local machine and an absolute URL would just cause a lot of hassle. Just in case my absolute URL is http://localhost/Linku2.5/
You generally want to go from the most specific rules to the least specific. Of the two things that you want to do, the first is the least specific, as (.*) can be anything. So we have to start with the much more specific and less arbitrary /profile/settings.
If these rules are in your htaccess file (in your case, in the Link2.5 directory), you don't want a leading slash, so simply:
# you only need to turn on once
RewriteEngine On
# Don't need absolute URLs, but you may need this line:
RewriteBase /Link2.5/
RewriteRule ^profile/settings lysettings.php [L]
Then, because your other rule is so general, you need to add some conditions so that you don't cause an infinite loop (the rewrite engine will continue to loop until the URI stops changing):
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ lyprofile.php?us=$1 [L,QSA]
If you know your "us" variable can only be numbers or letters, you can make the line with the rule a bit more specific:
RewriteRule ^([A-Za-z0-9]+)$ lyprofile.php?us=$1 [L,QSA]
etc.
Can you check this in vhosts config?
# Turn mod_rewrite on
RewriteEngine On
RewriteRule lyprofile\.php - [L]
RewriteCond %{REQUEST_URI} /(.*)
RewriteRule /(.*) lyprofile.php?us=$1 [L]
RewriteCond %{REQUEST_URI} /profile/settings
RewriteRule /profile/settings lysettings.php [L]
I'm having trouble with some URL rewriting.
All of the stuff below works fine, but I need to add a rule which removes querystrings from URLS.
site.com/page?a=b
will become
site.com/page
Can someone help out? I have done some reading on .htaccess but I find it terribly complex. Also, will need to know where in the file my new directives should appear.
Thanks.
# EE 404 page for missing pages
ErrorDocument 404 /index.php/404/index
# Simple 404 for missing files
ErrorDocument 404 "File Not Found"
# Rewriting will likely already be on, uncomment if it isnt
RewriteEngine On
RewriteBase /
# Block access to "hidden" directories whose names begin with a period. This
# includes directories used by version control systems such as Subversion or Git.
RewriteRule "(^|/)\." - [F]
# remove the www - Uncomment to activate
#
# RewriteCond %{HTTPS} !=on
# RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
# RewriteRule ^(.*)$ http://%1/$1 [R=301,L]
#
# Remove the trailing slash to paths without an extension
# Uncomment to activate
#
# RewriteRule ^(.*)/$ /$1 [R=301,L]
#
# Remove index.php
# Uses the "include method"
# http://expressionengine.com/wiki/Remove_index.php_From_URLs/#Include_List_Method
#
RewriteCond %{QUERY_STRING} !^(ACT=.*)$ [NC]
RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]{1,5})$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^/(home|inc|publishers|sidebars|about|include-template|testing|advertisers|products|sitemap|style|ad-choices|social-bar|search|404||members|P[0-9]{2,8}) [NC]
RewriteRule (.*) /index.php/$1 [L]
This would remove query string from url
RewriteRule ^(.*) /index.php/$1? [L] #remove query string
Hope it helps
I'm a little late for an answer, but since i was searching for a similar behaviour, i thought i should share it: you can also add a flag to a rewrite rule to remove the query string; the flag is [QSD], and it helps avoiding workarounds like the ? at the end ;-)
Here you can find more about this flag. I feel like pointing out that "This flag is available in [Apache] version 2.4.0 and later"
I would like to create rewrite rules in my .htaccess file to do the following:
When accessed via domain.com/abc.php: remove the file extension, append a trailing slash and load the abc.php file. url should look like this after rewrite: domain.com/abc/
When accessed via domain.com/abc/: leave the url as is and load abc.php
When accessed via domain.com/abc: append trailing slash and load abc.php. url should look like this after rewrite: domain.com/abc/
Remove www
Redirect to 404 page (404.php) when accessed url doesn't resolve to folder or file, e.g. when accessing either domain.com/nothingthere.php or domain.com/nothingthere/ or domain.com/nothingthere
Make some permanent 301 redirects from old urls to new ones (e.g. domain.com/abc.html to domain.com/abc/)
All php files sit in the document root directory, but if there is a solution that would make urls such as domain.com/abc/def/ (would load domain.com/abc/def.php) also work it would be great as well, but not necessary
So here is what I have at the moment (thrown together from various sources and samples from around the web
<IfModule mod_rewrite.c>
RewriteCond %{HTTPS} !=on
# redirect from www to non-www
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
# remove php file extension
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{THE_REQUEST} ^GET\ /[^?\s]+\.php
RewriteRule (.*)\.php$ /$1/ [L,R=301]
# add trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^.*[^/]$ /$0/ [L,R=301]
# resolve urls to matching php files
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)/$ $1.php [L]
With this the first four requirements seem to work, whether I enter domain.com/abc.php, domain.com/abc/ or domain.com/abc, the final url always ends up being domain.com/abc/ and domain.com/abc.php is loaded.
When I enter a url that resolves to a file that doesn't exists I'm getting an error 310 (redirect loop), when really a 404 page should be loaded. Additionally I haven't tried if subfolders work, but as I said, that's low priority. I'm pretty sure I can just slap the permanent 301 redirects for legacy urls on top of that without any issues as well, just wanted to mention it. So the real issue is really the non working 404 page.
I've had problems with getting ErrorDocument to work reliably with rewrite errors, so I tend to prefer to handle invalid pages correctly in my rewrite cascade. I've tried to cover a fully range of test vectors with this. Didn't find any gaps.
Some general points:
You need to use the DOCUMENT_ROOT environment variable in this. Unfortunately if you use a shared hosting service then this isn't set up correctly during rewrite execution, so hosting providers set up a shadow variable to do the same job. Mine uses DOCUMENT_ROOT_REAL, but I've also come across PHP_DOCUMENT_ROOT. Do a phpinfo to find out what to use for your service.
There's a debug info rule that you can trim as long as you replace DOCROOT appropriately
You can't always use %{REQUEST_FILENAME} where you'd expect to. This is because if the URI maps to DOCROOT/somePathThatExists/name/theRest then the %{REQUEST_FILENAME} is set to DOCROOT/somePathThatExists/name rather than the full pattern equivalent to the rule match string.
This is "Per Directory" so no leading slashes and we need to realise that the rewrite engine will loop on the .htaccess file until a no-match stop occurs.
This processes all valid combinations and at the very end redirects to the 404.php which I assume sets the 404 Status as well as displaying the error page.
It will currently decode someValidScript.php/otherRubbish in the SEO fashion, but extra logic can pick this one up as well.
So here is the .htaccess fragment:
Options -Indexes -MultiViews
AcceptPathInfo Off
RewriteEngine On
RewriteBase /
## Looping stop. Not needed in Apache 2.3 as this introduces the [END] flag
RewriteCond %{ENV:REDIRECT_END} =1
RewriteRule ^ - [L,NS]
## 302 redirections ##
RewriteRule ^ - [E=DOCROOT:%{ENV:DOCUMENT_ROOT_REAL},E=URI:%{REQUEST_URI},E=REQFN:%{REQUEST_FILENAME},E=FILENAME:%{SCRIPT_FILENAME}]
# redirect from HTTP://www to non-www
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
# remove php file extension on GETs (no point in /[^?\s]+\.php as rule pattern requires this)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_METHOD} =GET
RewriteRule (.*)\.php$ $1/ [L,R=301]
# add trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^.*[^/]$ $0/ [L,R=301]
# terminate if file exists. Note this match may be after internal redirect.
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L,E=END:1]
# terminate if directory index.php exists. Note this match may be after internal redirect.
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{ENV:DOCROOT}/$1/index.php -f
RewriteRule ^(.*)(/?)$ $1/index.php [L,NS,E=END:1]
# resolve urls to matching php files
RewriteCond %{ENV:DOCROOT}/$1.php -f
RewriteRule ^(.*?)/?$ $1.php [L,NS,E=END:1]
# Anything else redirect to the 404 script. This one does have the leading /
RewriteRule ^ /404.php [L,NS,E=END:1]
Enjoy :-)
You'll probably want to check if the php file exists before adding the tailing slash.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^.*[^/]$ /$0/ [L,R=301]
or if you really want a tailing slash for all 404 pages (so /image/error.jpg will become /images/error.jpg/, which I think is weird):
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^.*[^/]$ /$0/ [L,R=301]
I came up with this:
DirectorySlash Off
RewriteEngine on
Options +FollowSymlinks
ErrorDocument 404 /404.php
#if it's www
# redirect to non-www.
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [L,R=301,QSA]
#else if it has slash at the end, and it's not a directory
# serve the appropriate php
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1.php [L,QSA]
#else if it's an existing file, and it's not php or html
# serve the content without rewrite
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_URI} !(\.php)|(\.html?)$
RewriteRule ^ - [L,QSA]
#else
# strip php/html extension, force slash
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.*?)((\.php)|(\.html?))?/?$ /$1/ [L,NC,R=301,QSA]
Certainly not very elegant (env:redirect_status is quite a hack), but it passes my modest tests. Unfortunately I can't test the www redirection, as I'm on localhost, and has no real access to a server, but that part should work too.
You see, I used the ErrorDocument directive to specify the error page, and used the DirectorySlash Off request to make sure Apache doesn't interfere with the slash-appending fun. I also used the QSA (Query String Append) flag that, well, appends the query string to the request so that it's not lost. It looks kind of silly after the trailing slash, but anyhow.
Otherwise it's pretty straightforward, and I think the comments explain it pretty well. Let me know if you run into any trouble with it.
Create a folder under the root of the domain
Place a .htaccess in the above folder as RewriteRule ^$ index.php
Parse the URL
With PHP coding you can now strip the URL or file extension as required