Here's your original rule, with [L]
added to denote "last":
RewriteRule ^(.*)%25(.*)$ $1%$2 [L,R=301]
After that there are a few problems here. First, percent signs in RewriteRule
patterns have a special meaning; they denote the beginning of a back reference to a RewriteCond
. You can get around this by escaping them (using a backslash):
RewriteRule ^(.*)\%25(.*)$ $1%$2 [L,R=301]
Second, when you insert a %
in to the replacement, it doesn't then go on to treat that as part of a uri-encoded piece. It translates to a literal percent sign. In the original url you are receiving, the first %25"
is converted into a literal percent sign as well. So the above rule will result in literal %25
s or a literal %2b
in the url instead of resolving to %
or +
. So you have to manually resolve these yourself.
RewriteRule ^(.*)\%25(.*)$ $1%$2
RewriteRule ^(.*)\%2b(.*)$ $1+$2 [L,R=301]
Finally, since you don't just have a single 25
after the initial %
, but potentially many, use [N]
to denote "next". This basically means "start the process over from the beginning, but use my new url as the input". So this will deal with any number of 25
s after the percent:
RewriteRule ^(.*)\%25(.*)$ $1%$2 [N]
RewriteRule ^(.*)\%2b(.*)$ $1+$2 [L,R=301]
Note: This should work if you are setting up your rule in the regular apache configs. If you are setting it up as an .htaccess
, leading slashes are omitted from the string checked against the regex, in which case you have to add them back in yourself:
RewriteRule ^(.*)\%25(.*)$ /$1%$2 [N]
RewriteRule ^(.*)\%2b(.*)$ /$1+$2 [L,R=301]
UPDATE: I don't have the ability to test right now, but looking at the docs, I just saw an option NE
for "no escape" that makes percents work as regular encoding markers in the result. If I understand correctly, that means the rule can be simplified to this:
RewriteRule ^(.*)\%25(.*)$ $1%$2 [NE,N,L,R=301]
But again, this is untested, and I've never actually used the NE
flag so I may be misunderstanding it. If you test this and find that it works, let me know and I'll remove this UPDATE and just fix the above answer to include this simpler version.
It would seem like you've already tried this, it's the most obvious answer (as poncha pointed out) and it's probably the most likely to show up in a mod_rewrite tutorial/guide. By exlcuding the directory using a RewriteCond
, noting that the match of the condition is against the %{REQUEST_URI}
, which begins with a /
":
<IfModule mod_rewrite.c>
Options -MultiViews
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !^/sub_dir
RewriteCond %{REQUEST_FILENAME} .*\.(jpeg|jpg|gif|png)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . /public/404.php [L]
RewriteCond %{REQUEST_URI} !^/sub_dir
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
EDIT:
Looking at what you've tried, this also is wrong. You don't want the leading slash in the match of the RewriteRule
when it is in an htaccess file:
<IfModule mod_rewrite.c>
Options -MultiViews
RewriteEngine On
RewriteRule ^sub_dir - [L]
RewriteBase /
RewriteCond %{REQUEST_FILENAME} .*\.(jpeg|jpg|gif|png)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . /public/404.php [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
Best Answer
You can try with the below rules.