RewriteCond to match query string parameters in any order

后端 未结 3 634
天涯浪人
天涯浪人 2020-12-02 19:35

I have a URL which may contain three parameters:

  1. ?category=computers
  2. &subcategory=laptops
  3. &product=dell-inspiron-15

I

相关标签:
3条回答
  • 2020-12-02 20:02

    You can achieve this with multiple steps, by detecting one parameter and then forwarding to the next step and then redirecting to the final destination

    RewriteEngine On
    
    RewriteCond %{QUERY_STRING} ^category=([^&]+) [NC,OR]
    RewriteCond %{QUERY_STRING} &category=([^&]+) [NC]
    RewriteRule ^index\.php$ $0/%1
    
    RewriteCond %{QUERY_STRING} ^subcategory=([^&]+) [NC,OR]
    RewriteCond %{QUERY_STRING} &subcategory=([^&]+) [NC]
    RewriteRule ^index\.php/[^/]+$ $0/%1
    
    RewriteCond %{QUERY_STRING} ^product=([^&]+) [NC,OR]
    RewriteCond %{QUERY_STRING} &product=([^&]+) [NC]
    RewriteRule ^index\.php/([^/]+/[^/]+)$ http://store.example.com/$1/%1/? [R,L]
    

    To avoid the OR and double condition, you can use

    RewriteCond %{QUERY_STRING} (?:^|&)category=([^&]+) [NC]
    

    as @TrueBlue suggested.

    Another approach is to prefix the TestString QUERY_STRING with an ampersand &, and check always

    RewriteCond &%{QUERY_STRING} &category=([^&]+) [NC]
    

    This technique (prefixing the TestString) can also be used to carry forward already found parameters to the next RewriteCond. This lets us simplify the three rules to just one

    RewriteCond &%{QUERY_STRING} &category=([^&]+) [NC]
    RewriteCond %1!&%{QUERY_STRING} (.+)!.*&subcategory=([^&]+) [NC]
    RewriteCond %1/%2!&%{QUERY_STRING} (.+)!.*&product=([^&]+) [NC]
    RewriteRule ^index\.php$ http://store.example.com/%1/%2/? [R,L]
    

    The ! is only used to separate the already found and reordered parameters from the QUERY_STRING.

    0 讨论(0)
  • 2020-12-02 20:06

    1) In case You just need to check that all parameters are in url:

       RewriteCond %{QUERY_STRING} (^|&)category\=computers($|&)
       RewriteCond %{QUERY_STRING} (^|&)subcategory\=laptops($|&)
       RewriteCond %{QUERY_STRING} (^|&)product\=dell\-inspiron\-15($|&)
       RewriteRule ^$ http://store.example.com/computers/laptops/dell-inspiron-15/? [R=301,L]
    

    2) In case You need exact set of parameters:

     RewriteCond %{QUERY_STRING} ^&*(?:category\=computers|subcategory\=laptops|product\=dell\-inspiron\-15)(?!.*&\1(?:&|$))(?:&+(category\=computers|subcategory\=laptops|product\=dell\-inspiron\-15)(?!.*&\1(?:&|$))){2}&*$
     RewriteRule ^$ http://store.example.com/computers/laptops/dell-inspiron-15/? [R=301,L] 
    

    This rule is generated by 301 redirect generator

    0 讨论(0)
  • 2020-12-02 20:14

    I take a slightly different approach for this sort of thing, leveraging ENV VARs set and read by mod_rewrite. I find it more readable / maintainable to refer to the backreferences by name like this, and these ENV VARs can be reused later in request processing too. Overall I think it's a more powerful and flexible approach than the accepted answer here. In any case, it works well for me. I've copied my gist below in its entirety:

    From https://gist.github.com/cweekly/5ee064ffffd551e1997d4c

    # Mod_rewrite is great at manipulating HTTP requests.
    # Using it to set and read temp env vars is a helpful technique.
    #
    # This example walks through fixing a query string:
    # Extract good query params, discard unwanted ones, reorder good ones, append one new one.
    #
    # Before: /before?badparam=here&baz=w00t&foo=1&bar=good&mood=bad
    # After: /after?foo=1&bar=good&baz=w00t&mood=happy
    #
    # Storing parts of the request (or anything you want to insert into it) in ENV VARs is convenient.
    # Note the special RewriteRule target of "-" which means "no redirect; simply apply side effects"
    # This lets you manipulate the request at will over multiple steps.
    #
    # In a RewriteRule, set custom temp ENV VARs via [E=NAME:value]
    # Note it's also possible to set multiple env vars
    # like [E=VAR_ONE:hi,E=VAR_TWO:bye]
    #
    # You can read these values using %{ENV:VAR_NAME}e <- little "e" is not a typo
    #
    # Tangent:
    # Note you can also read these env vars the same way, if you set them via SetEnvIf[NoCase]
    # (It won't work to use SetEnv, which runs too early for mod_rewrite to pair with it.)
    #
    # Regex details:
    # (?:) syntax means "match but don't store group in %1 backreference"
    #      so (?:^|&) is simply the ^ beginning or an & delimiter
    #      (the only 2 possibilities for the start of a qs param)
    # ([^&]+) means 1 or more chars that are not an & delimiter
    
    RewriteCond %{QUERY_STRING} (?:^|&)foo=([^&]+)
    RewriteRule ^/before - [E=FOO_VAL:%1]
    
    RewriteCond %{QUERY_STRING} (?:^|&)bar=([^&]+)
    RewriteRule ^/before - [E=BAR_VAL:%1]
    
    RewriteCond %{QUERY_STRING} (?:^|&)baz=([^&]+)
    RewriteRule ^/before - [E=BAZ_VAL:%1]
    
    RewriteRule ^/before /after?foo=%{FOO_VAL}e&bar=%{BAR_VAL}e&baz=%{BAZ_VAL}e&mood=happy [R=301,L]
    

    P.S. This is not a copy/pasteable solution to your question, but rather shows exactly how to handle this kind of problem. Armed w this understanding, leveraging it for your example will be completely trivial. :)

    0 讨论(0)
提交回复
热议问题