flat url rewriting: stripped of path in HTML anchor - html

In C:\xampp\htdocs\myname\myproject\index.html I have
About Us
This should link to C:\xampp\htdocs\myname\myproject\aboutus.html.
In my localhost I would like the url to look like this:
localhost/myname/myproject/
localhost/myname/myproject/aboutus
However, I can't seem to figure out how to write the url rewriting rules to make this work.
The only thing that works is if I put the path in the html:
About Us
But I don't want to do that.
My C:\xampp\htdocs\myname\myproject\.htaccess file:
<IfModule mod_rewrite.c>
# Enable url rewriting
RewriteEngine On
RewriteBase /myname/myproject/
# Don't rewrite explictly requested paths
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# URL rewriting rules
#TEST RewriteRule aboutus /myname/myproject/aboutus.html
RewriteRule ^([0-9]+).html/$ $1\.html
</IfModule>
What am I doing wrong here?

Try changing:
RewriteRule ^([0-9]+).html/$ $1\.html
to
RewriteRule ^([0-9A-Za-z\-_]+)/?$ $1\.html
What you're doing wrong is the regex. You're only allowing the characters 0-9 in your page name. Also notice the /? at the end. That's for making the / optional.

Related

Why is ".html" appearing on the end of my urls in browser? [duplicate]

How to remove .html from the URL of a static page?
Also, I need to redirect any url with .html to the one without it. (i.e. www.example.com/page.html to www.example.com/page ).
I think some explanation of Jon's answer would be constructive. The following:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
checks that if the specified file or directory respectively doesn't exist, then the rewrite rule proceeds:
RewriteRule ^(.*)\.html$ /$1 [L,R=301]
But what does that mean? It uses regex (regular expressions). Here is a little something I made earlier...
I think that's correct.
NOTE: When testing your .htaccess do not use 301 redirects. Use 302 until finished testing, as the browser will cache 301s. See https://stackoverflow.com/a/9204355/3217306
Update: I was slightly mistaken, . matches all characters except newlines, so includes whitespace. Also, here is a helpful regex cheat sheet
Sources:
http://community.sitepoint.com/t/what-does-this-mean-rewritecond-request-filename-f-d/2034/2
https://mediatemple.net/community/products/dv/204643270/using-htaccess-rewrite-rules
To remove the .html extension from your urls, you can use the following code in root/htaccess :
RewriteEngine on
RewriteCond %{THE_REQUEST} /([^.]+)\.html [NC]
RewriteRule ^ /%1 [NC,L,R]
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^ %{REQUEST_URI}.html [NC,L]
NOTE: If you want to remove any other extension, for example to remove the .php extension, just replace the html everywhere with php in the code above.
Also see this How to remove .html and .php from URLs using htaccess` .
This should work for you:
#example.com/page will display the contents of example.com/page.html
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.+)$ $1.html [L,QSA]
#301 from example.com/page.html to example.com/page
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*\.html\ HTTP/
RewriteRule ^(.*)\.html$ /$1 [R=301,L]
With .htaccess under apache you can do the redirect like this:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)\.html$ /$1 [L,R=301]
As for removing of .html from the url, simply link to the page without .html
page
You will need to make sure you have Options -MultiViews as well.
None of the above worked for me on a standard cPanel host.
This worked:
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.html [NC,L]
For those who are using Firebase hosting none of the answers will work on this page. Because you can't use .htaccess in Firebase hosting. You will have to configure the firebase.json file. Just add the line "cleanUrls": true in your file and save it. That's it.
After adding the line firebase.json will look like this :
{
"hosting": {
"public": "public",
"cleanUrls": true,
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}
}
Thanks for your replies. I have already solved my problem. Suppose I have my pages under http://www.yoursite.com/html, the following .htaccess rules apply.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /html/(.*).html\ HTTP/
RewriteRule .* http://localhost/html/%1 [R=301,L]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /html/(.*)\ HTTP/
RewriteRule .* %1.html [L]
</IfModule>
Good question, but it seems to have confused people. The answers are almost equally divided between those who thought Dave (the OP) was saving his HTML pages without the .html extension, and those who thought he was saving them as normal (with .html), but wanting the URL to show up without. While the question could have been worded a little better, I think it’s clear what he meant. If he was saving pages without .html, his two question (‘how to remove .html') and (how to ‘redirect any url with .html’) would be exactly the same question! So that interpretation doesn’t make much sense. Also, his first comment (about avoiding an infinite loop) and his own answer seem to confirm this.
So let’s start by rephrasing the question and breaking down the task. We want to accomplish two things:
Visibly remove the .html if it’s part of the requested URL (e.g. /page.html)
Point the cropped URL (e.g. /page) back to the actual file (/page.html).
There’s nothing difficult about doing either of these things. (We could achieve the second one simply by enabling MultiViews.) The challenge here is doing them both without creating an infinite loop.
Dave’s own answer got the job done, but it’s pretty convoluted and not at all portable. (Sorry Dave.) Łukasz Habrzyk seems to have cleaned up Anmol’s answer, and finally Amit Verma improved on them both. However, none of them explained how their solutions solved the fundamental problem—how to avoid an infinite loop. As I understand it, they work because THE_REQUEST variable holds the original request from the browser. As such, the condition (RewriteCond %{THE_REQUEST}) only gets triggered once. Since it doesn’t get triggered upon a rewrite, you avoid the infinite loop scenario. But then you're dealing with the full HTTP request—GET, HTTP and all—which partly explains some of the uglier regex examples on this page.
I’m going to offer one more approach, which I think is easier to understand. I hope this helps future readers understand the code they’re using, rather than just copying and pasting code they barely understand and hoping for the best.
RewriteEngine on
# Remove .html (or htm) from visible URL (permanent redirect)
RewriteCond %{REQUEST_URI} ^/(.+)\.html?$ [nocase]
RewriteRule ^ /%1 [L,R=301]
# Quietly point back to the HTML file (temporary/undefined redirect):
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^ %{REQUEST_URI}.html [END]
Let’s break it down…
The first rule is pretty simple. The condition matches any URL ending in .html (or .htm) and redirects to the URL without the filename extension. It's a permanent redirect to indicate that the cropped URL is the canonical one.
The second rule is simple too. The first condition will only pass if the requested filename is not a valid directory (!-d). The second will only pass if the filename refers to a valid file (-f) with the .html extension added. If both conditions pass, the rewrite rule simply adds ‘.html’ to the filename. And then the magic happens… [END]. Yep, that’s all it takes to prevent an infinite loop. The Apache RewriteRule Flags documentation explains it:
Using the [END] flag terminates not only the current round of rewrite
processing (like [L]) but also prevents any subsequent rewrite
processing from occurring in per-directory (htaccess) context.
Resorting to using .htaccess to rewrite the URLs for static HTML is generally not only unnecessary, but also bad for you website's performance. Enabling .htaccess is also an unnecessary security vulnerability - turning it off eliminates a significant number of potential issues. The same rules for each .htaccess file can instead go in a <Directory> section for that directory, and it will be more performant if you then set AllowOverride None because it won't need to check each directory for a .htaccess file, and more secure because an attacker can't change the vhost config without root access.
If you don't need .htaccess in a VPS environment, you can disable it entirely and get better performance from your web server.
All you need to do is move your individual files from a structure like this:
index.html
about.html
products.html
terms.html
To a structure like this:
index.html
about/index.html
products/index.html
terms/index.html
Your web server will then render the appropriate pages - if you load /about/, it will treat that as /about/index.html.
This won't rewrite the URL if anyone visits the old one, though, so it would need redirects to be in place if it was retroactively applied to an existing site.
I use this .htacess for removing .html extantion from my url site, please verify this is correct code:
RewriteEngine on
RewriteBase /
RewriteCond %{http://www.proofers.co.uk/new} !(\.[^./]+)$
RewriteCond %{REQUEST_fileNAME} !-d
RewriteCond %{REQUEST_fileNAME} !-f
RewriteRule (.*) /$1.html [L]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([^.]+)\.html\ HTTP
RewriteRule ^([^.]+)\.html$ http://www.proofers.co.uk/new/$1 [R=301,L]
Making my own contribution to this question by improving the answer from #amit-verma (https://stackoverflow.com/a/34726322/2837434) :
In my case I had an issue where RewriteCond %{REQUEST_FILENAME}.html -f was triggering (believing the file existed) even when I was not expecting it :
%{REQUEST_FILENAME}.html was giving me /var/www/example.com/page.html for all these cases :
www.example.com/page (expected)
www.example.com/page/ (also quite expected)
www.example.com/page/subpage (not expected)
So the file it was trying to load (believing if was /var/www/example.com/page.html) were :
www.example.com/page => /var/www/example/page.html (ok)
www.example.com/page/ => /var/www/example/page/.html (not ok)
www.example.com/page/subpage => /var/www/example/page/subpage.html (not ok)
Only the first one is actually pointing to an existing file, other requests were giving me 500 errors as it kept believing the file existed and appending .html repeatedly.
The solution for me was to replace RewriteCond %{REQUEST_FILENAME}.html -f with RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.html -f
Here is my entire .htaccess (I also added a rule to redirect the user from /index to /) :
# Redirect "/page.html" to "/page" (only if "/pages.html" exists)
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{THE_REQUEST} /(.+)\.html [NC]
RewriteRule ^(.+)\.html$ /$1 [NC,R=301,L]
# redirect "/index" to "/"
RewriteRule ^index$ / [NC,R=301,L]
# Load "/page.html" when requesting "/page" (only if "/pages.html" exists)
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.html -f
RewriteRule ^ /%{REQUEST_URI}.html [QSA,L]
Here is a result example to help you understand all the cases :
Considering I have only 2 html files on my server (index.html & page.html)
www.example.com/index.html => redirects to www.example.com
www.example.com/index => redirects to www.example.com
www.example.com => renders /var/www/example.com/index.html
www.example.com/page.html => redirects to www.example.com/page
www.example.com/page => renders /var/www/example.com/page.html
www.example.com/page/subpage => returns 404 not found
www.example.com/index.html/ => returns 404 not found
www.example.com/page.html/ => returns 404 not found
www.example.com/test.html => returns 404 not found
No more 500 errors 🚀
Also, just to help you debug your redirections, consider disabling the network cache in your browser (as old 301 redirections my be in cache, wich may cause some headaches 😅):
first create a .htaccess file and set contents to -
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html
next remove .html from all your files eg. test.html became just test and also if you wanna open a file from another file then also remove .html from it and just file name
Use a hash tag.
May not be exactly what you want but it solves the problem of removing the extension.
Say you have a html page saved as about.html and you don't want that pesky extension you could use a hash tag and redirect to the correct page.
switch(window.location.hash.substring(1)){
case 'about':
window.location = 'about.html';
break;
}
Routing to yoursite.com#about will take you to yoursite.com/about.html. I used this to make my links cleaner.
To remove the .html extension from your URLs, you can use the following code in root/htaccess :
#mode_rerwrite start here
RewriteEngine On
# does not apply to existing directores, meaning that if the folder exists on server then don't change anything and don't run the rule.
RewriteCond %{REQUEST_FILENAME} !-d
#Check for file in directory with .html extension
RewriteCond %{REQUEST_FILENAME}\.html !-f
#Here we actually show the page that has .html extension
RewriteRule ^(.*)$ $1.html [NC,L]
Thanks
For this, you have to rewrite the URL from /page.html to /page
You can easily implement this on any extension like .html .php etc
RewriteRule ^(.*).html$ $1.html [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.html [NC,L]
You will get a URL something like this:
example.com/page.html to example.com/page
Please note both URLs below will be accessible
example.com/page.html and example.com/page
If you don't want to show page.html
Try this
RewriteRule ^(.*).html$ $1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.html [NC,L]
More info here
If you have a small static website and HTML files are in the root directory.
Open every HTML file and make the next changes:
Replace href="index.html" with href="/".
Remove .html in all local links. For example: "href="about.html"" should look like "href="about"".
RewriteEngine On
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /html/(.*).html\ HTTP/
RewriteRule .* https://example.com/html/%1 [R=301,L]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /html/(.*)\ HTTP/
RewriteRule .* %1.html [L]
it might work because its working in my case
RewriteRule /(.+)(\.html)$ /$1 [R=301,L]
Try this :) don't know if it works.

HTML always loaded from cache

I have a index file under www/ and apache config set DirectoryIndex to that index.html
If I use this link
example.com/
Everything works fine since the html itself has meta tag to not use cache
but if I use
example.com (Which in url bar will redirect to example.com/)
//Note: In chrome, the initiator for this also change to example.com
The index is always fetched from cache
And the second way is how normal end user type in the address. Can you guys explain what is going on?
example.com/ is treated differently than example.com. The slash indicates that a URL is a folder and not a document. Adding extra slashes (such as example.com///) will also consititute an independent caching in this regard.
I would recommend forcing a single trailing slash, which can be done with the following .htaccess:
RewriteEngine On
# Assuming you're running at domain root. Change to working directory if needed.
RewriteBase /
# www check
# If you're running in a subdirectory, then you'll need to add that in
# to the redirected url (http://www.example.com/subdirectory/$1
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L]
# Trailing slash check
# Don't fix direct file links
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ $1/ [L,R=301]
# Finally, forward everything to your front-controller (index.php)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php [QSA,L]
More information regarding this can be found here.
Hope this helps! :)

remove html extension using htaccess file

i know this is a very common topic but none of the solutions works for me.
i have tried several answers:
answer 1
answer 2
answer 3
and the referal links.
The htaccess code that i am using:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)\.html$ /$1 [L,R=301]
then i changed my links from services.html to services i.e. i removed the extension and also removed the extension from the file name using ftp.
what i get is the page code displayed in my browser not the actual page.
I have checked mod_rewrite on my server and it works correctly using this code
RewriteEngine On
Options +FollowSymLinks
RewriteRule ^joomla\.html http://www.joomla.org/? [R=301,L]
Your file should still have the .html extension on the server, otherwise the server/browser won't interpret it as html but text instead (which is the reason you see the code in your browser). So rename the files on your server using ftp again.
In order to let your server serve the file /test.html when the url /test is accessed, you want to rewrite that internally, i.e.:
RewriteRule ^test[^/]$ test.html
The ^ is to match the start of the string, the $ matches the end, so this will only rewrite if the url exactly matches test. It will rewrite that request to test.html. The rewrite is internal, this means it won't redirect the browser (the url in the address bar doesn't change). There is also the external rewrite ([R] appended to the rule), which redirects the browser.
This rule also only matches urls that don't end with a trailing slash ([^/] means "not slash"). We will handle urls with a trailing slash later.
You could create a custom RewriteRule for each page that you want to rewrite:
RewriteRule ^foo[^/]$ foo.html
RewriteRule ^bar[^/]$ bar.html
This is a lot of work if you have many pages, so you may want to rewrite all urls, e.g. foo or bar should be rewritten to foo.html / bar.html, and foo/bar should be rewritten to foo/bar.html.
You can also use a regular expression to match all requests. But you should first check if foo isn't actually a directory (which could contain a index.html and be a sub-directory you want to serve). Also you want to check if foo isn't really a file on your server's file system. There are two rewrite conditions to check that (see the RewriteCond directive):
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
Now you can add a rewrite rule for all requests:
RewriteRule ^(.+[^/])$ $1.html
$1 is the content of the first capture group, a capture group in a regex is an expression placed in () brackets. . matches any character, the + modifier means "one or more".
Note that this would cause a rewrite loop resulting in a 500 error (see this answer), so you need to also add a rewrite condition to check if the <request>.html file actually exists on the file system:
RewriteCond %{REQUEST_FILENAME}.html -f
Also you might not want to rewrite urls that already have a .html extension. I don't think it's necessary, as you already have the rule above which would in that case check for <file>.html.html which probably shouldn't exist. But if you have to deal with that, you could add another condition:
RewriteCond %{REQUEST_FILENAME} !^.+\.html$
So putting it altogether your rewrite rule looks like this:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
# RewriteCond %{REQUEST_FILENAME} !^.+\.html$ # not really necessary
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.+[^/])$ $1.html
The only thing that you need to handle now are urls that have a trailing slash. For that we just add a simple external rewrite rule that removes the trailing slash if the url doesn't actually match a directory:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ $1 [R,L]
This rule matches only urls that end with / (regex /$) and captures everything before the trailing slash as a group (regex (.+)), then redirects to the group (which doesn't contain the slash). Notice the R and L flags behind the rule. R is for redirect, which redirects the browser (url in address bar changes). L is for last, meaning no other rules will be applied after this one, though rules will be applied again after the rewrite, and this is where the other rule gets applied.
TL;DR
RewriteBase /
# handle trailing slashes (if not a directory)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ $1 [R,L]
# rewrite rule that internally adds the .html extension
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.+[^/])$ $1.html
like #simon suggested the correct file is:
# handle trailing slashes (if not a directory)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ $1 [R,L]
# rewrite rule that internally adds the .html extension
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteCond %{REQUEST_FILENAME} !^.+\.html$
RewriteRule ^(.+[^/])$ $1.html
also i had to delete all text files with the same name from the server through ftp.

Enforce trailing slash policy htaccess with HTTPS

I was wondering if someone could lend a hand with a small .htaccess issue.
Inside the .htaccess file is this for example:
Options -Indexes
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
# Normal
RewriteRule ^about$ ./about.html [L,NC]
RewriteRule ^news$ ./news.html [L,NC]
RewriteRule ^other$ ./other.html [L,NC]
This works great if you want to enforce HTTPS and NOT have a forward slash after domain.com/about
My question is:
How do I enforce HTTPS and add the forward slash at the end like so;
https://www.domain.com/about/
or allow a user to add the forward slash at the end without it redirecting them to a 404 error page.
Also they are just HTML pages inside the main folder on the server.
Once apon a time, you would have to create folders "about" , "news", "others" etc and place an index.html file in each with all the images, css and js etc just to get the forward slash.
I hope this can be done.
Thanks!
You need to add a rule to enforce the slash then change your existing rewrites so that they match against it:
Options -Indexes -Multiviews
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
# enforce the trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]+[^/])$ /$1/ [R,L]
# Normal
RewriteRule ^about/$ ./about.html [L,NC]
RewriteRule ^news/$ ./news.html [L,NC]
RewriteRule ^other/$ ./other.html [L,NC]
Also, to be on the safe side, turn off Multiviews.

.htaccess rewriterule /state/city/

This will take a bit of explanation so I hope I don't lose everyone here.
I needed to get something like the following:
http://example.com/results.html?state=iowa&city=davenport
turned into:
http://example.com/iowa/davenport/
I was able to accomplish this with the use of these two rewriterules:
RewriteRule ^([A-Za-z0-9-]+)/?$ cities.html?state=$1 RewriteRule
^([A-Za-z0-9-]+)/([A-Za-z0-9-]+)/?$ results.html?state=$1&city=$2
The problem is that in the backend there is "some code somewhere" that is getting broken as a result of the second rewriterule. It has to do with filling in a select box based on the results of another one selected (I don't think that matters though). I think the problem is in that I'm modifying too broadly the /state/city.
Here is a copy of my full (modified for security) .htaccess file:
IndexIgnore *
AddHandler application/x-httpd-php5 .html .htm
RewriteRule ^([A-Za-z0-9-]+)/?$ cities.html?state=$1
RewriteRule ^([A-Za-z0-9-]+)/([A-Za-z0-9-]+)/?$ results.html?state=$1&city=$2
<Files .htaccess>
order allow,deny
deny from all
</Files>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example.com
RewriteRule (.*) http://www.example.com/$1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
<IfModule mod_suphp.c>
suPHP_ConfigPath /home/USER
<Files php.ini>
order allow,deny
deny from all
</Files>
The code that its screwing up is very complex and its someone else's code. After a couple of hours I've been unable to wade through all of their stuff to even come close to what I may be able to change on their end to get things working.
Does anyone have ANY ideas on what I could do to avoid this problem? I really only have 3 .html files that I'm funneling my frontend code through so I had tried something like a
my rewriterules
and same with using just "files" instead of filesMatch. Everything I've come up with breaks something else or the entire site in one way or another.
First: (i) hostgator won't enable or give you access to rewrite logs; (ii) your suPHP config has syntax errors and hostgator almost certainly does spme of this and the .htacess / php.ini denials in its own root / vhost configs. However, I'll focus on the mod_rewrite elements:
RewriteEngine On
RewriteRule ^([A-Za-z0-9-]+)/?$ cities.html?state=$1
RewriteRule ^([A-Za-z0-9-]+)/([A-Za-z0-9-]+)/?$ results.html?state=$1&city=$2
RewriteCond %{HTTP_HOST} ^example.com
RewriteRule (.*) http://www.example.com/$1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
I am also assuming that you don't have any .htaccess files in subdirectories with the rewrite engine enabled as these could preempt this under rewrite "Per Directory" precedence rules.
Rules (3) is a simple domain redirector. Rule (4) is a draconian: redirect any URI which is not an existing file or directory to index.php in the current directory, but leaving the query string intact.
Rule (1) and (2) are your new rules. As Mike says, you should include the [L] but since the files cities.html and results.html exist it won't match anyway.
I am curious as to why the trailing slach in the URIs is optional. Better to decide and to fix this.
The issue is that the match criteria for (1) and (2) are two broad and are picking up URIs intended for the general catchall (4). You need to lock this down to make these mutually exclusive. One why is to mine your access logs (which are available with hostgator) to find the standard URIs which the application expects and check that none match (1) or (2) -- However, since most will include a ".", this probably isn't the case. But check.
The other issue is whether the existing scripts use absolute or relative references e.g. <img src="images/myimage.png"> in any output HTML. Here the browser has asked for http://www.example.com/texas/houston say and will therefore look for http://www.example.com/texas/images/myimage.png which doesn't match (1), (2) or (3) and therefore is caught by (4) and passed to /index.php. Ditto CSS files etc. Hence they won't 404 and index.php will get confused and send some default response which will hopelessly confuse the browser.
However, again analysis of the access logs (in this case or USIs with a referrer http://www.example.com/texas/houston) will show you if this is going on.
If your app uses standard subdirectories then you might be able to fix this by a rule (3.1) which looks something like
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond $1/$2 -f
RewriteRule .*?(images|css|styles)/(.+) $1/$2 [L]
though the details will depend on the rest of your application.
I was able to solve it by changing my (relevant) .htaccess entries to the following:
RewriteEngine On
RewriteRule ^([A-Za-z0-9-]+)/?$ cities.html?state=$1
RewriteCond %{REQUEST_URI} !^/signup/
RewriteRule ^([A-Za-z0-9-]+)/([A-Za-z0-9-]+)/?$ results.html?state=$1&city=$2
RewriteCond %{HTTP_HOST} ^example.com
RewriteRule (.*) http://www.example.com/$1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
The addition being:
RewriteCond %{REQUEST_URI} !^/signup/
HostGator was able to find that the issue was /signup somewhere in a log somewhere, never did find out which log they were able to look at but I assume it was something I didn't have access to.