I try write a rewrite rule on an apache webserver configuration in the httpd.conf file, which should replace every GET parameter key which contains &foo= to &poo= but shouldn't change any other GET parameter. For example:
https://test.com/imb/rs/search?test=abc&foo=123&test2=def&foo=456
Should be changed to:
https://test.com/imb/rs/search?test=abc&poo=123&test2=def&poo=456
I tried it with:
RewriteCond %{QUERY_STRING} ^(.*)&foo=(.*)$
RewriteRule ^(.*)$ $1?%1?&poo=%2 [NC]
But it only changed the last occurrence of foo to poo.
My httpd.conf file is structured as follows:
<Directory ~ "^/imb/rs/*">
Options Indexes FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
RewriteEngine on
RewriteCond %{QUERY_STRING} ^(.*)&foo=(.*)$
RewriteRule ^(.*)$ $1?%1&poo=%2 [NC]
</Directory>
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{QUERY_STRING} ^(.*)&foo=(.*)$
RewriteRule ^(.*)$ $1?%1&poo=%2 [NC]
</IfModule>
The /imb/rs/ part is written because the url starts with https://test.com/imb/rs/ and continues after that. I thought that would match my case.
Does anyone have an idea how I could solve this?
CodePudding user response:
I found this solution which works only with 1 occurrence, not with multiple.
This one takes only the first occurrence:
RewriteCond %{QUERY_STRING} (.*?)foo(.*) [NC]
RewriteRule ^ %{REQUEST_URI}?%1poo%2 [NC]
This one takes only the last occurrence:
RewriteCond %{QUERY_STRING} (.*)foo(.*) [NC]
RewriteRule ^ %{REQUEST_URI}?%1poo%2 [NC]
But I couldn't find a way to replace all of them.
CodePudding user response:
<Directory ~ "^/imb/rs/*"> Options Indexes FollowSymLinks AllowOverride All Order allow,deny Allow from all RewriteEngine on RewriteCond %{QUERY_STRING} ^(.*)&foo=(.*)$ RewriteRule ^(.*)$ $1?%1&poo=%2 [NC] </Directory> <IfModule mod_rewrite.c> RewriteEngine on RewriteCond %{QUERY_STRING} ^(.*)&foo=(.*)$ RewriteRule ^(.*)$ $1?%1&poo=%2 [NC] </IfModule>
There are a few issues here. The <Directory>
container is not going to match the request, so the mod_rewrite directives inside this container are not processed. Only the mod_rewrite directives outside the <Directory>
container are processed, but this will only replace the last instance of &foo=
in the query string (since the regex is greedy and the rewrite engine makes just a single pass in a vHost/server context).
<Directory ~ "^/imb/rs/*">
You are mixing regex and wildcard syntax. However, this should be an absolute filesystem path, not a URL-path, as this appears to be ("url starts with https://test.com/imb/rs/
"). But you do not need to use the regex version of the <Directory>
directive here anyway. I'm assuming /imb/rs
is a physical directory and not simply a virtual URL-path?
AllowOverride All
You are explicitly enabling .htaccess
overrides. If you do have a .htaccess
file that contains mod_rewrite directives in this directory then this will completely override the <Directory>
container in the server config. You should probably be disabling .htaccess
overrides altogether.
Order allow,deny Allow from all
These are Apache 2.2 directives and are formerly deprecated on Apache 2.4 (which I would assume you are using). You should be using the equivalent Require all granted
instead. (But you do need to make sure you are using Apache 2.4 directives throughout - do not mix the two.)
Options Indexes FollowSymLinks
Aside: Are you intentionally allowing mod_autoindex to generate directory listings of your content? Generally, this should be disabled (ie. remove Indexes
from this rule).
Try the following instead:
<Directory "/absolute/file/path/to/imb/rs">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
RewriteEngine On
RewriteCond %{QUERY_STRING} (.*)&foo=(.*)
RewriteRule (.*) $1?%1&poo=%2 [L]
</Directory>
And remove the rule from outside the <Directory>
container.
So, the rule you had in the beginning was basically OK. The start-of-string and end-of-string anchors are not required here, since the regex is greedy. The NC
flag is not required. The L
flag is not strictly required, but would be if you add any more rules later.