Home > Blockchain >  How to search and replace GET parameters with mod_rewrite
How to search and replace GET parameters with mod_rewrite

Time:03-01

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.

  • Related