8

If I want to apply a rule to only some files in apache2.conf, I can use <FilesMatch>.

For example:

<FilesMatch ".(gif|jpg|jpeg|png|mpg|avi)$">
    deny from env=hotlink
</FilesMatch>

But is there a opposite to FilesMatch, i.e. a FilesNotMatch?

What I want to achieve is:

<FilesMatch ".(gif|jpg|jpeg|png|mpg|avi)$">
    <FilesNotMatch "ban">
        deny from env=hotlink
    </FilesNotMatch>
</FilesMatch>

(deny hotlinking of all images on a server BUT banners)

Or do you have a suggestion how I could modify my regexp to not match anything that contains "ban" ?

BlaM
  • 3,816
  • 5
  • 26
  • 27

2 Answers2

8

Sadly there doesn't seem to be a way to negate a file match in Apache.

However, the regular expression library that Apache uses is PCRE (Perl Compatible Regular Expressions). This means you have the full power of Perl's regexes, including their negative lookbehind and lookahead assertions. These are fairly complicated and powerful features. I can't be certain that this will work, especially without knowing the full layout of your images, but you might be able to use something like:

<FilesMatch "(?<!ban).*\.(gif|jpg|jpeg|png|mpg|avi)$">
David Pashley
  • 23,151
  • 2
  • 41
  • 71
1

Almost correct - you need to use \b(?!.*ban.*)(.+)\.(gif|jpg|jpeg|png|mpg|avi)$ regexp for such exception.

Tomasz Pala
  • 398
  • 1
  • 6
  • I tried "\b(?!/test.php)" to match any file other than test.php and it didn't work. – David Spector Jan 02 '20 at 14:06
  • Well, you just need to follow my example. As you've ignored 'ending$' (and escaping dot via '\.') you have probably did some tests earlier - up to the point, where rexexp fails, but somehow your comment doesn't specify the place, where it happens. I won't reproduce your test-case, but I might *guess* it has something to do with '/' you've introduced... – Tomasz Pala Jan 26 '20 at 10:18
  • Thanks! I almost always have trouble with regexps. Now I'm trying ^(?!(test\.php))$ and this still doesn't work. It doesn't match "xx" when it should. I'm using the online regexp tester https://regex101.com/ to test. And when I try your example, it matches "a.gif" when it should not match. Probably, I'm not understanding the original question, and misunderstanding the ?! operator. – David Spector Jan 27 '20 at 11:32
  • Consider ^(?!(test\.php))$ - if you remove the negation, that doesn't match your "xx", what's left? ^()$ - i.e. empty string. Try ^(?!(test\.php)).+$. As for my example - it's supposed to match "a.gif", but do not match "ban.gif" and that is what happens. The accepted answer matches "ban.gif" and so is wrong... – Tomasz Pala Jan 30 '20 at 14:32
  • If you ask me, the Perl Regular Expression library, and all the products that use it, need a true negation operator. Trying to force a "look-ahead" feature to work well can obviously be done, but only with great difficulty. PCRE needs to be extended. – David Spector Jan 31 '20 at 17:05