Trying to use negative condition in RewriteCond...not working...stumped

I am trying to test a site at a webhost using their temporary URL (a URL they provide for that purpose before I make the DNS changes to make the site “live”).

To access the site using the temporary URL one has to use a URL of the form…

http://account12617.hosting.com/~username (that’s a made up, non-existant URL).

The problem is the ~username part of that URL. All my links within the site are relative NOT absolute. Many of these links are hard coded (as relative) into the site pages and are not under the control of any CMS so I can’t change some CMS value to take into account the entire URL above.

When I go click on a link - for example a page called some-page, what happens is that Apache returns a 404 page not found error when the link is resolved as http://account12617.hosting.com/some-page

The page actually exists and CAN be accessed at http://account12617.hosting.com/~username/some-page

So the solution is to somehow have Apache, and more specifically mod_rewrite insert the “~username” part in every URL that does NOT have that in it.

I have tried all kinds of things with no success.

This is the latest mod_rewrite I tried - again with no success.


<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteBase /

   RewriteCond !~username 
   RewriteRule ^(.*)$ /~username/$1  
</IfModule>

Apache returns a 404 page not found error and the URL in the browser is reset to http://account12617.hosting.com/404.html

Anybody got any tips or clue as to how to do this? What is wrong with my RewriteCond and/or my RewriteRule?

Any help would be most appreciated.

Thanks.

Carlos

Carlos,

You’ve actually got a couple of problems with your mod_rewrite code but I’ll get to that in a moment.

If you can create a subdomain for your ~username account, why not put all the files in that subdirectory (the ~username subdirectory of the main domain) where it can be directly accessed (via the subdomain) without playing around with a temporary directory? Okay, just a thought … I’ll jump back into your box and address your problem.

When you use a subdirectory and change the level of the request, you’re confusing the visitors’ browsers when they go to look for relative links. My signature’s tutorial has both options for you to resolve that problem (and you’ll probably want to use the <BASE> tag). Well, with the problem resolved, it’s time to review your code:


[COLOR="#FF0000"]<IfModule mod_rewrite.c>
# Ah! I feel a Standard Rant coming on:

[rant #4][indent]The definition of an idiot is someone who repeatedly does the same thing
expecting a different result.  Asking Apache to confirm the existence of
ANY module with an <IfModule> ... </IfModule> wrapper is the same thing
in the webmaster world.  DON'T BE AN IDIOT!  If you don't know whether
a module is enabled, run the test ONCE then REMOVE the wrapper as it is
EXTREMELY wasteful of Apache's resources (and should NEVER be allowed
on a shared server).[/indent][/rant 4]

[indent]NO! I'm [I]NOT[/I] calling you an idiot. You are simply unaware of what your
code is doing to (abusing) the server. Check ONCE and get rid of this code
as this test is performed MULTIPLE times for [B]each and every[/B] file request!
It should [B]NEVER [/B]be in an .htaccess file.[/indent][/COLOR]

   RewriteEngine On
[COLOR="#FF0000"]   RewriteBase /
# Why? This is not needed![/COLOR]

   RewriteCond !~username
[COLOR="#FF0000"]# The syntax of the RewriteCond statement is
# RewriteCond [string to test, i.e., %{REQUEST_URI}] [string to match] [optional flags]
# Moreover, unless your ~username is fixed (a constant), you will need to change this
# value and a RewriteCond statement is not the place to do that![/COLOR]

   RewriteRule ^(.*)$ /~username/$1
[COLOR="#0000FF"]# Wasteful - consider testing the "it doesn't match above" [I]then[/I]
# RewriteRule .? ~username%{REQUEST_URI} [L][/COLOR]
[COLOR="#FF0000"]</IfModule>[/COLOR]

Hi Dklynn,

Yes I could do that but the problem of being able to access relative URL’s on an HTTP_HOST value that is NOT the actual domain that it will be when I change the DNS to point to the new host location, would still remain. So that would not alleviate me having to either figure out how to use .htaccess to rewrite such URL’s or go through the pain of hard coding the new host (at the subdomain) for testing purposes and then change the URL’s again when the domain goes live.

When you use a subdirectory and change the level of the request, you’re confusing the visitors’ browsers when they go to look for relative links.

I think I understand your point but I am not doing this for the sake of visitors. I am doing this to try and test the site to make sure everything works fine before going live with it.

Admittedly some visitors might come along and be a bit confused but again my aim is not to make the site URL’s super user friendly at this point in the move. It’s just to make sure everything works before making it go live.


[COLOR=#FF0000]<IfModule mod_rewrite.c>
[INDENT]...If you don't know whether 
a module is enabled, run the test ONCE then REMOVE the wrapper as it is 
EXTREMELY wasteful of Apache's resources (and should NEVER be allowed 
on a shared server).[/INDENT]
[/COLOR]

Interesting. I’ve always used the IfModule because EVERY single piece of .htaccess code example I have EVER seen (and I mean ever seen) has used it. As such it seemed advisable to use it though I do see your point and have removed it from my code as you suggest.

Though I also wonder what will happen if my host removes the mod_rewrite module for some reason but then again that is as likely to happen as that they stop using Apache.

RewriteEngine On
   RewriteBase /
# Why? This is not needed!

Again…it’s what my CMS spits out for me to put into the .htaccess file. So I have used it as such. And like with the IfModule EVERY single piece of code I have ever seen that uses the mod_rewrite module turns it on which would indicate that there is some reason for always having “RewriteEngine On” in the code.

I’d rather be safe and leave such statements in than take them out on sites that belong to clients where I want nothing to go wrong. Especially regarding code that I see included everywhere.

Incidentally I removed the “RewriteEngine On” to test out what you said and when I do that…NOTHING gets rewritten at all so I think you must be mistaken about it being okay to take it out.

   RewriteCond !~username 
[COLOR=#FF0000]# The syntax of the RewriteCond statement is
# RewriteCond [string to test, i.e., %{REQUEST_URI}] [string to match] [optional flags]
# Moreover, unless your ~username is fixed (a constant), you will need to change this 
# value and a RewriteCond statement is not the place to do that!

[/COLOR]Well…the ~username is a constant in the sense that EVERY URL on the site must include it as part of the URL. So I am not sure what you mean by saying that I will need to change this value.

I do see where my example code was missing something in the RewriteCond.

It should have been “RewriteCond %{REQUEST_URI} !username [NC]”. In other words I am testing to see if “username” is part of the URL. If it’s not then and only then do I want the RewriteRule to execute.

   RewriteRule ^(.*)$ /~username/$1
[COLOR=#0000FF]# Wasteful - consider testing the "it doesn't match above" [I]then[/I]
# RewriteRule .? ~username%{REQUEST_URI} [L][/COLOR]

Now that is a very interesting way to do it. I will definitely use that!

I am not quite sure what the “.?” stands for though I know question marks are often used to indicate non-greedy and the dot of course is any character I believe. But I am just not sure why you used the .? is all.

The following is what I have thus far…but it’s still not working correctly. It works as desired on my localhost copy of Apache but for some reason when I transfer this code to my host it continues to revert to a host of “http://account12617.hosting.com/” without the ~username included in the URL.

Whereas when I run the exact same code on my local copy of Apache it correctly rewrites all URL’s that are missing the ~username as “http://account12617.hosting.com/~username/”.

Not sure why that difference in result yet.

Here’s my code…


RewriteCond %{HTTP_HOST} !^somedomain.com\\.local$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !username [NC]
RewriteRule .? ~username/index.php%{REQUEST_URI} [R,E]

somedomain.com.local is just a local copy of the site that I run locally for testing and development.

http://account12617.hosting.com/~username/ is the temporary URL given to me by the host.

When the site goes live it will simply be http://somedomain.com (without the .local ending).

Thanks again for your input! Much appreciated.

Carlos

Hi Carlos,

Okay, the subdomain seemed to be a way to resolve your problem IF the subdomain actually linked directly to the subdirectory of the main domain.

My point is that you will “lose” your supporting files if they’re relative linked (rather than absolute links). As the tutorial states, you can get around this with either absolute links OR the <BASE> tag.

As for the <IfModule>, it’s okay to use in the httpd.conf file but, because the .htaccess must be parsed MULTIPLE times for each and every file request, it makes no sense to run a test repeatedly. Glad that you got that.

Also, understand that WordPress et al do that so amateur webmasters don’t whine about having their website disabled by their code - which code Apache doesn’t understand would do!

Hosts know these days that .htaccess and mod_rewrite are indispensable to webmasters so they’re unlikely to disable them (and they are just as unlikely to get rid of Apache).

And if your GPS told you to take a left in the middle of a bridge … Aw, the important thing is to UNDERSTAND what the code you use is doing for you. If you don’t, why would you use it? Anyway, the RewriteBase directive was designed to undo a mod_alias redirection. In effect, it changes the root directory of your mod_rewrite code to that specified. If your .htaccess is in the DocumentRoot, the RewriteBase / becomes immediately superfluous and only slows down your serving requested files.

As for RewriteEngine on, it’s to ensure that Apache’s mod_rewrite is not in the comment mode, i.e., RewriteEngine off operates like /* and RewriteEngine on operates like */. It’s more of a safety measure to use it (ONCE - I’m stunned at those who keep repeating RewriteEngine on like a mantra!) at the start of your mod_rewrite code section. Oh, I never said to remove RewriteEngine on - I left it in black print and used the red for “errors” or code to delete.

Okay, if ~username is a constant, great! All that much easier to make calls to your website via a subdomain. Yeah, yeah, yeah, you already said that you didn’t want to do that. Anyway, the point was that the syntax of the RewriteCond statement was incorrect => 500 error! I note that you want to use the No Case flag on a {REQUEST_URI} variable so let me just remind you that 'nix servers ARE case sensitive so, if you direct the mod_rewrite to be case insensitive, you WILL end up with 404 errors, i.e., remove the [NC] flag!

Using %{REQUEST} takes all the guesswork out of whether there should be a leading / or not and the .? is a safer way to account for just the DocumentRoot (http://domain) request. Obviously, .? is zero or one of any character is required (same as (.*) without creating a duplicate Apache variable for {REQUEST_URI}) and it will ALWAYS return a true (match).

RewriteEngine on
# Only apply to a subdomain (or other colocated domain)
RewriteCond %{HTTP_HOST} !^somedomain.com\\.local$ [NC]
# The No Case flag is fine here as the {HTTP_HOST} is not case sensitive

# The request is not an existing file
RewriteCond %{REQUEST_FILENAME} !-f

# The request is not an existing directory
RewriteCond %{REQUEST_FILENAME} !-d

# The request is not to a directory (or file) containing username
# This should NOT use the No Case flag!
RewriteCond %{REQUEST_URI} !username [COLOR="#FF0000"][NC][/COLOR]

# Redirect to {REQUEST_URI} within the ~username subdirectory
RewriteRule .? ~username[COLOR="#FF0000"]/index.php[/COLOR]%{REQUEST_URI} [R,E]
# What was the index.php doing there?
# Redirection flag is 302 status (temporary) by default so it's better to specify R=301
# Another syntax error with the Environment flag:

[indent]With the [E], or [env] flag, you can set the value of an environment variable. 
Note that some environment variables may be set after the rule is run, thus 
unsetting what you have set. See the Environment Variables document for 
more details on how Environment variables work.

The full syntax for this flag is:

[E=VAR:VAL] [E=!VAR]

VAL may contain backreferences ($N or %N) which will be expanded.

Using the short form, [E=VAR], you can set the environment variable 
named VAR to an empty value.

The form, [E=!VAR], allows to unset a previously set environment variable named VAR.

Environment variables can then be used in a variety of contexts, 
including CGI programs, other RewriteRule directives, or CustomLog 
directives.[/indent]

BTW, I thought that E was the Environment flag but you made me look it up (because I never use it)! WHY did you believe you had to use it?

Regards,

DK

The ~username is apparently linked to a subdirectory by the hosting setup internally.

Okay, if ~username is a constant, great! All that much easier to make calls to your website via a subdomain. Yeah, yeah, yeah, you already said that you didn’t want to do that. Anyway, the point was that the syntax of the RewriteCond statement was incorrect => 500 error! I note that you want to use the No Case flag on a {REQUEST_URI} variable so let me just remind you that 'nix servers ARE case sensitive so, if you direct the mod_rewrite to be case insensitive, you WILL end up with 404 errors, i.e., remove the [NC] flag!

I end up with no such errors. Even when using the NC flag. At least not errors caused by a difference in case.

I appreciate your further input but in all frankness removing or keeping the NC flag seems to have no relevance to what I am asking. Still I will test with both the NC flag set and leaving out to see if that affects anything.

RewriteEngine on
# Redirect to {REQUEST_URI} within the ~username subdirectory
RewriteRule .? ~username[COLOR=#FF0000]/index.php[/COLOR]%{REQUEST_URI} [R,E]
# What was the index.php doing there?
[/quote]

The index.php MUST be there or the CMS that I am using will not be able to show the page requested.  All requests are funneled through index.php.  


> 
BTW, I thought that E was the Environment flag but you made me look it up (because I never use it)! WHY did you believe you had to use it?



The 'E' flag was my attempt to get around my Apache not recognizing the END flag.  I was trying to use that flag to avoid redirections per Apache documentation of what the END flag is.  I forgot that the ENV flag also goes by the E letter.  

Thanks for pointing that out. 

Incidentally I have given up trying to rewrite the URL's.  It's too much of a pain.  I am just going to change the DNS entries to point to the new hosting location and keep a close eye on the domain to make sure things are working okay while going live.  

Carlos