.htaccess - What does the - mean on this RewriteRule?

RewriteRule ^(dir1|file1) - [L]

If this rule IS THE CASE then other rewrite rules should NOT apply.

Since we are on a .htaccess context, having only the [L] will be useless.

So, we need two things:

1) To have the - sign.

2) To have this rule before all other RewriteRules on our .htaccess file.

If all above assumptions are correct and precise, I would like to ask:

I’ve been reading that:

RewriteEngine on rewriteRule a b [L] rewriteRule b c

Most people would think that when requesting /a, the internally requested file would be /b because of the [L] flag. Well, it’s not. The last requested file will actually be /c. To understand why, you need to understand how mod_rewrite handles a request in a per-directory context.

source: colder.ch - Truth about the Last mod_rewrite’s modifier (revisited)

Hence, the question:

What does the - mean, and what does it do on this context?

Thanks a lot.
:slight_smile:

When rewriting, Apache processes all rules in the .htaccess in sequence.

  • When a rule matches and has a last flag, the process will start over from rule one.
  • If after processing all rules the URL has changed by one or more of the rules and no [L] flag was hit along the way (which would have restarted the process), the process will start over from rule one.
  • If none of the rules match, the rewriting is done

Following that logic it’s indeed easy to see that your example ends up serving /c

If however you put a rule with “-” before the other rules this doesn’t seem to apply (just tested it) and you can indeed use it to avoid rewriting on any URL that matches that rule.

Probably Apache is smart enough to think “Well, if I start this over, I will run into this rule again, do nothing again, and I will end up in an infinite loop so let’s just serve this and be done with it”.
Not sure if that’s the logic behind it, but it is the observed behavior :slight_smile:

So, according to Apache manual:

A dash indicates that no substitution should be performed (the existing path is passed through untouched). This is used when a flag [like L flag?] needs to be applied without changing the path.

So… :slight_smile: please confirm if my assumption is correct: the rule will be applied to /c because, since there is no dash - sign, we will stay with /b path, because it will be “untouched” by the next rule on the line? Is that it ? (if not, please, calm down… I will get there. :D:D).

Can you give a complete .htaccess example of what you mean? I’m afraid I don’t really follow what you’re saying.

Sure thing. :slight_smile:

The point is to create AND ALSO understand all lines of a .htaccess file that I need to put in place, in order to the Zend project to work both locally and on a shared host environment.

So. :slight_smile:

At this moment I have this:


RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !^(filename1|filename2)
RewriteRule ^(dir1|dir2|dir3) - [L]

RewriteRule ^\\.htaccess$ - [F]
RewriteCond %{REQUEST_URI} =""

RewriteRule ^.*$ /public/index.php [NC,L]
RewriteCond %{REQUEST_URI} !^/public/.*$

RewriteRule ^(.*)$ /public/$1
RewriteCond %{REQUEST_FILENAME} -f

RewriteRule ^.*$ - [NC,L]
RewriteCond %{REQUEST_FILENAME} !\\.(js|JS|Js|jS|ico|Ico|ICO|zip|ZIP|Zip|rar|RAR|Rar|mov|MOV|Mov|MPEG4|Mpeg4|mpeg4|mp4|Mp4|gif|GIF|Gif|jpg|JPG|Jpg|jpeg|JPEG|Jpeg|PNG|Png|png|CSS|Css|css|DOC|Doc|doc|PDF|Pdf|pdf|DOCX|Docx|DocX|docX|docx|WMV|Wmv|wmv|MPEG|Mpeg|mpeg|AVI|Avi|avi|MPG|Mpg|mpg|FLV|Flv|flv|PPT|Ppt|ppt|PPTX|PptX|Pptx|pptx|txt|TXT|txt)$


RewriteRule ^public/.*$ /public/index.php [NC,L]

This was copy paste from the internet, and the more I ask and read, the more I realise the “dummyness” here. :slight_smile: Both mine (for copy/pasting) and from the source).

Instead, I wish to understand line by line, and use only the necessary instructions. :slight_smile:

So I’m trying to create a new:


#I have a long comment about why we should use this.
Options +FollowSymlinks

#I have another long comment why we MUST have this.
RewriteEngine On

Then I stopped :slight_smile: because I didn’t understand the - sign here:


RewriteCond %{REQUEST_FILENAME} !^(filename1|filename2)
RewriteRule ^(dir1|dir2|dir3) - [L]

Note: I realise that the Condition will always return true, so the condition is wrong and need to be changed.

Request:
I wish to have (and understand) a rule on this .htaccess file that DON’T redirect some directories or files. (for simple testing proposes and so on).

PS - As you may imagine, I do have A LOT of trillion other questions, but this is just about the - meaning here. :smiley:

(:

ScallioXTX … :slight_smile: I’ve complicated my own question haven’t I ?

Maybe I can presume that the dash tells:

Don’t rewrite this “thing” (state of ignorance).
And if any of the above prefixes are catched on the URL (or is it URI ?), by the webserver http deamon, then my friend that will be the [L] last rewrite rule that I will follow, and the URL you provide will be as is.

:headbang:

And for my last try to be more clear, here are the doubts, on all it’s glory.


#+FollowSymLinks must be enabled for any rules to work 
#this is a  security 
#requirement of the rewrite engine. Normally it's enabled 
#in the root and you 
#shouldn't have to add it, but it doesn't hurt to do so.
Options +FollowSymlinks

#Apache scans all incoming URL requests, checks for matches in our #.htaccess file 
#and rewrites those matching URLs to whatever we specify.
#to enable runtime rewriting engine
RewriteEngine On
    
#this tells mod_rewrite to leave the URL unchanged 
#(the dash part -) and quit 
#other rewwrite processing rules if the requested 
#segment has one of those 
#prefixes (that's what we asking when we use the ^ sign)
#on the list. If the 
#prefix is in the list, all subsequent Rewrite Rules are skipped.
#So to avoid some files OR directories to be redirected we use:
RewriteRule ^(somefile|somedir|someotherfile) – [L]

1) Don’t we need a condition here before these previous RewriteRule ?

#this will allow direct linkage to this extensions, 
#regardless the case sensitive.
RewriteCond %{REQUEST_FILENAME} !\\.(js|ico|zip|rar|mov|mpeg4|mp4|gif|jpg|png|css|doc|pdf|docx|wmv|mpeg|avi|mpg|flv|ppt|pptx|txt)$ - [NC]

2) Will the [NC] flag deal with all case variations here?

#if the request uri has not public...
RewriteCond %{REQUEST_URI} !^/public/.*$
#rewrite to public something...
RewriteRule ^(.*)$ /public/$1

3) Why do we have $1 and not /public/index.php on our RewriteRule?

#rewrite all requests that start with public, to public/index.php 
#and if that's the case, don't run any other rule.
RewriteRule ^public/.*$ /public/index.php [NC,L]

4) since this is the last rule, can we remove the L flag ?

  1. That depends on what you want to do :wink:
    If you only want to make sure no rewrites are done for the directories put in that list, then no, you don’t need a condition.

  2. Yes :slight_smile:

  3. This is basically a security thing. It redirects all requests that are not to public/ to public/. Personally I find the use of a public/ directory weird an annoying since there are better ways to solve file hiding. Just put them in a place Apache cannot serve at all, like one directory up from the public_html directory.
    That will provide more security than any .htaccess rule / option / whatever could ever give you.

  4. Sure you could, but I always leave them on there, in case I add a rule later and forget to add [L] to that rule. That’s a mistake that’s fairly easy to make.

I may be wrong, but the reason I choose this path is due to the fact that I’m using Zend Framework projects. Since I’m not a proficient user of that framework, I need to stay with the structure that zf tool creates (that it’s still not that bad).

Another reason (and I may be wrong again), for doing like this is related with the shared host upload. Once I end up working locally, I wish to ease the process as much as I can, by “mirrow” the local files structure with the one the shared host forces me to. At the end, and so I hope, is just a question of “Uploading” and all will work just fine. :slight_smile:

I take your advice on this one.

I will also add an - L with the - NC flag, so that I can have: - [NC, L] ; hoping that, with this, if a specific file extension is found, there’s no need to run a rewrite for anything else.

Thanks a lot for your time and patience, again and again.
You sure are a Sir Guru. :wink:

I will probably want to add a hotlink protection here as well and, if you see any other gap that I may be missing, please let me know. :smiley:

K. Regards
m.

Why do you check for an extension? I wouldn’t do that, because it limits in you in your options. What if you ever want to serve a ZIP file through PHP?
Using your way, you can’t.

There’s an easy way to serve everything through index.php


RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .? public/index.php [L]

That is: if the requested URL (or URI, see URI vs URL) is not a directory, and not a directory, forward it to index.php
That way index.php becomes a sort of catch all for everything that doesn’t exist. Neat eh? :slight_smile:

If you post your complete current .htaccess (I’m guessing the one you posted in #1 is outdated by now) I’d be happy to comment on it :slight_smile:

#+FollowSymLinks must be enabled for any rules to work, this is a security #requirement of the rewrite engine. Normally it's enabled in the root and we #shouldn't have to add it, but it doesn't hurt to do so.
Options +FollowSymlinks

#Apache scans all incoming URL requests, checks for matches in our #.htaccess file 
#and rewrites those matching URLs to whatever we specify.
#So, to enable runtime rewriting engine
RewriteEngine On
#this tells mod_rewrite to leave the URL unchanged (the dash part -) and #quit 
#other rewwrite processing rules if the requested segment has one of those #prefixes (that's what we asking when we use the ^ sign), on the list. If the #prefix is in the list, all subsequent Rewrite Rules are skipped.
#So to avoid some files OR directories (both) to be redirected we use:

RewriteRule ^(somefile|somedir|someotherfile) – [L]
#I don't need any condition for this rule. Somehow (it seems to find that I'm #talking about URI or URL).
#this will allow direct linkage to this extensions, regardless the case #sensitive.
#so, for example JPG or jPg will also be taken by this condition. (The NC #part)
#We have also add a L flag so that,at the end, if the condition matches, #don't check other CONDITIONS and go to the NEXT rule.
#RewriteCond %{REQUEST_FILENAME} #!\\.(js|ico|zip|rar|mov|mpeg4|mp4|gif|jpg|png|css|doc|pdf|docx|wmv|mpeg#|avi|mpg|flv|ppt|pptx|txt)$ - [NC, L]

#a better approach to the previous one,and to avoid all this typing seems to #be:
#ispsis verbis: if the requested URL or URI is not a directory, and not a #directory [sic] file, forward it to index.php
#That way index.php becomes a sort of catch all for everything that doesn't #exist.
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .? public/index.php [L]


QUESTION: with the -d and -f usage we don’t need the NC flag ?


#rewrite a request of / internally to /public/index.php for 
#any URI path unless it already starts with /public/
RewriteCond %{REQUEST_URI} !^/public/.*$
RewriteRule ^(.*)$ /public/$1

QUESTION: Should we put a L flag here?


#rewrite all requests that start with public, to public/index.php and if that's #the case, don't run any other rule. 
RewriteRule ^public/.*$ /public/index.php [NC,L]

The clean htaccess without my comments:



Options +FollowSymlinks

RewriteEngine On

RewriteRule ^(somefile|somedir|someotherfile) – [L]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .? public/index.php [L]

RewriteCond %{REQUEST_URI} !^/public/.*$
RewriteRule ^(.*)$ /public/$1
RewriteRule ^public/.*$ /public/index.php [NC,L]

I will now read about URI and URL finally, I’m always not getting their difference, and I notice that a lot of folks who talk about that, don’t know either. ehehe I will have a look to your link now. :slight_smile:

Update:

Options +FollowSymlinks

RewriteEngine On

RewriteRule ^(testes) – [L]

#to not allow hotlinking to images
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\\.)?mysite.com [NC]
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\\.)?mysite.dev [NC]
RewriteRule \\.(jpg|jpeg|png|gif)$ - [NC,F,L]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .? public/index.php [L]

RewriteCond %{REQUEST_URI} !^/public/.*$
RewriteRule ^(.*)$ /public/$1
RewriteRule ^public/.*$ /public/index.php [NC,L]
Options +FollowSymlinks

RewriteEngine On

That’s the default minimum. Nothing to say, moving along.


RewriteRule ^(testes) – [L]

(1) Since you just want to match one directory (I assume?) you don’t need the parentheses
(2) Are you sure you need this rule? Would be matched by any the following rules?


#to not allow hotlinking to images
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\\.)?mysite.com [NC]
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\\.)?mysite.dev [NC]
RewriteRule \\.(jpg|jpeg|png|gif)$ - [NC,F,L]

This won’t work. RewriteConds are anded by default. So it is: if RewriteCond 1 holds and RewriteCond 2 holds and RewriteCond 3 holds …
Since the three rules are mutually exclusive this will never happen, you need to make them or instead of and, which you can do with the [OR] flag.

Also, you can remove the parentheses around the s from http(s)?

Lastly, don’t forget to escape all dots in there.


#to not allow hotlinking to images
RewriteCond %{HTTP_REFERER} !^$ [OR]
RewriteCond %{HTTP_REFERER} !^https?://(www\\.)?mysite[COLOR="Red"]\\[/COLOR].com [NC,OR]
RewriteCond %{HTTP_REFERER} !^https?://(www\\.)?mysite[COLOR="Red"]\\[/COLOR].dev [NC]
RewriteRule \\.(jpg|jpeg|png|gif)$ - [NC,F,L]


RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .? public/index.php [L]

Nothing to add.


RewriteCond %{REQUEST_URI} !^/public/.*$
RewriteRule ^(.*)$ /public/$1

See post #8
I’m not a fan of this public/ directory. But it’s not wrong.
I would however stay clear from the :redhot: (.*) :redhot: atom and change it to


RewriteCond %{REQUEST_URI} !^/public/.*$
RewriteRule .? /public%{REQUEST_URI}

That is a bit faster and nicer IMO.


RewriteRule ^public/.*$ /public/index.php [NC,L]

[/QUOTE]


Why? The block with !-f and !-d already catches this. You can remove this last block.

No I’m not. I never was.
The point is to have a place to work, without the framework to route that.
I found it usefull some times, to just write something to a directory without ZF to know about it.

But I thought that, since… I have this rule:
RewriteCond %{REQUEST_FILENAME} !-d

and since “testes” IS a directory, it will not rewrite as well.
So, no need for the first one. Yes?

Note: What I found really funny about all this is that, by chance, or not, the ZF atually don’t name their FOLDER controllers, the same way the actions are called. So, apache will always be aware where, on the URL like:
http://www.mysite.com/team/list
“team” is, NOT a directory, but an action, hence, the rewrite WILL occur.

(: I have a question here, but I can’t yet, formulate it. :smiley:

I will give it a try on this:


Options +FollowSymlinks
RewriteEngine On

RewriteCond %{HTTP_REFERER} !^$ [OR]
RewriteCond %{HTTP_REFERER} !^https?://(www\\.)?mysite\\.com [NC,OR]
RewriteCond %{HTTP_REFERER} !^https?://(www\\.)?mysite\\.dev [NC]
RewriteRule \\.(jpg|jpeg|png|gif)$ - [NC,F,L]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .? public/index.php [L]

RewriteCond %{REQUEST_URI} !^/public/.*$
RewriteRule .? /public%{REQUEST_URI}

Thanks a lot for your endless patience with all those questions. :slight_smile:
Márcio

Yes :slight_smile:

The term “action” is something only ZF knows about, Apache has no idea. All apache knows (and cares about) is that /team/list is not a directory. It couldn’t care less about what it is.
Indeed, it’s a nice little trick :slight_smile:

Feel free to get back to me when you do :slight_smile: