Your regular expression can fail against attackers doing attacks by encoding their URLs; fail2ban will not detect those, neither your regular expression; But you can modify your regexpes to match these encoded URLs also even in mixed form (partly encoded, and partly not); create regular expressions to replace each character with something like --
(c|%63|%43)
Here I replace c with the above; this will match c, and it's capital and small form in encoded URLs. In fail2ban you need to replace the % with a %% --
(c|%%63|%%43)
So I write .php as --
(\.|%%2E)(p|%%70|%%50)(h|%%68|%%48)(p|%%70|%%50)
You may begin the regular expression with (?i) in fail2ban or define it as (?i:<your regexp>) elsewhere to ignore case of the character (so C and c are alike and %2e and %2E is also alike.
To convert URLs to their encoded form I've created a simple script --
#! /usr/bin/ruby
# Converts the input string to a regular expression which will match the string either in the URL encoded form or mixed or unencoded form and case insensitively
# First argument is the string.
input = ARGV[0].dup
input.gsub!(/a/,'(a|%61|%41)')
input.gsub!(/b/,'(b|%62|%42)')
input.gsub!(/c/,'(c|%63|%43)')
input.gsub!(/d/,'(d|%64|%44)')
input.gsub!(/e/,'(e|%65|%45)')
input.gsub!(/f/,'(f|%66|%46)')
input.gsub!(/g/,'(g|%67|%47)')
input.gsub!(/h/,'(h|%68|%48)')
input.gsub!(/i/,'(i|%69|%49)')
input.gsub!(/j/,'(j|%6A|%4A)')
input.gsub!(/k/,'(k|%6B|%4B)')
input.gsub!(/l/,'(l|%6C|%4C)')
input.gsub!(/m/,'(m|%6D|%4D)')
input.gsub!(/n/,'(n|%6E|%4E)')
input.gsub!(/o/,'(o|%6F|%4F)')
input.gsub!(/p/,'(p|%70|%50)')
input.gsub!(/q/,'(q|%71|%51)')
input.gsub!(/r/,'(r|%72|%52)')
input.gsub!(/s/,'(s|%73|%53)')
input.gsub!(/t/,'(t|%74|%54)')
input.gsub!(/u/,'(u|%75|%55)')
input.gsub!(/v/,'(v|%76|%56)')
input.gsub!(/w/,'(w|%77|%57)')
input.gsub!(/x/,'(x|%78|%58)')
input.gsub!(/y/,'(y|%79|%59)')
input.gsub!(/z/,'(z|%7A|%5A)')
input.gsub!(/\./,'(\.|%2E)')
input.gsub!(/-/,'(-|%2D)')
puts input
The first argument to this script will be your text input.