views:

375

answers:

3

I've been reading through a previous solution to a recursive mod_rewrite problem that is similar to what I'm trying to do, the difference is I'm sending all queries through an index.php file and so don't need to specify the script within the query.

Essentially I want to recursively convert any number of parameters within a search engine friendly url:

example.com/param1/val1/param2/val2/...

to a regular query string:

example.com/index.php?param1=val1&param2=val2&...

So far I've been unsuccessful in in my attempts though:

RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^([^/]+)/([^/]+) $1=$2&%1 [L]
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^(.*)$ index.php?%1 [L]

Would anyone be able to offer any suggestions?

A: 

yes...

Taken from the examples here:

http://iirf.codeplex.com/sourcecontrol/changeset/view/62027?projectName=IIRF#981491

This ruleset iteratively translates a pair of URL path segments to a querystring n=v segment.

# handle case with no query string.  This rule fires the first time through,
# and converts the first pair of URL path segments to a n=v query string segment.  
RewriteRule ^/(?!index\.php)([^\?\/]+)/([^\?\/]+)/([^\?]+)$ /$3?$1=$2

# handle the case where there is an existing query string, and more than one pair of 
# URL path segments remaining. This rule fires potentially multiple times.
RewriteRule ^/(?!index\.php)([^\?\/]+)/([^\?\/]+)/([^\?]+)\?(.+)$ /$3?$4&$1=$2


# Handle the case with a query string, and exactly one pair of URL path segments. 
# This fires once (last).
# It fires when there is an even number of segments. 
RewriteRule ^/(?!index\.php)([^\?\/]+)/([^\?\/]+)\?([^\?]+)$ /help.cfm?$3&$1=$2  [L]

# Handle the case with no query string, and exactly one pair of URL path segments. 
# This fires once (last).
RewriteRule ^/(?!index\.php)([^\?\/]+)/([^\?\/]+)$ /help.cfm?$1=$2  [L]


# Handle the edge case, where there is an odd number of segments, which is invalid
# for these purposes. 
#
# This fires once, after all the other pairs have been parsed.  In fact the filter
# cannot know that there is an odd number of segments until it does all the matching.
# So at the end we see, we have one left over segment, and we 
# redirect to a 404 page.

RewriteRule ^/(?!index\.php)([^\/\?]+)\?([^\?]+)$ /ResourceNotFound.php  [L]

# Handle the edge case where there is only one segment. This is also an error
# in this ruleset.
RewriteRule ^/(?!index\.php)([^\/\?]+)$ /FoundOnlyOneSegment.php  [L]

This ruleset might not be exactly what you want but it illustrates the approach. It was not developed for mod_rewrite, but for IIRF, which is a rewriter for IIS. But the syntax should be the same for mod_rewrite, so these rules should just work.

I don't know if mod_rewrite has a logging facility, or a command-line test capability, but IIRF does, which makes it easier to see how individual rules work, or the outcome of sets of rules.

IIRF has an iteration limit that defaults to 10. There's a way to raise that limit to 30, which is pretty high, but still not infinite. That means it won't work for "any number of parameters". It can convert up to 15 pairs of params. I don't know if mod_rewrite has a similar limit.

Cheeso
A: 

I copied the solution from that other question and modified it like this:

RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^(.*/)?([^/]+)/([^/]+) $1?$2=$3&%1 [L]
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^.*$ index.php?%1 [L]

It does nearly the same thing, except in the first rule, the first match is optional and in the second rule, the match is on whatever is left after all the other pairs are matched.

For an odd number of parameters, the first parameter is ignored.

One note, if you expect to have a lot of parameters, you may have to change some settings.

Add something like this to your .htaccess file

RewriteOptions MaxRedirects=20

and something like this to your apache conf file

LimitInternalRecursion 20

Instead of "20" pick whatever number of recursions (pairs) you need to allow (the default is 10).

bmb
It works well for an even number of parameters (though doesn't recognise an odd number). Thanks for taking a look, much appreciated ;-)
dGreaves
dGreaves, I'm not sure what you want it to do with an odd number of parameters. Change the ^$ to ^.*$ on the last line and at least it won't error out.
bmb
nothing myself really, just thought I'd mention it ;-)
dGreaves
What if there are 21 pairs?
Gumbo
Gumbo, lol. I guess I could have been clearer. I hope the new edit addresses your question.
bmb
A: 

Try these rules:

RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
RewriteRule ^([^/]+)/([^/]+)(/(.*))?$ /$4?$1=$2 [N,QSA]
RewriteRule ^$ index.php [L]

The first rule is to exclude requests for existing files. The second rule will do the work and rewrite each name and value pair. And the third rule is to rewrite the final URI to index.php.

Gumbo
Hi there thanks for the reply, this works ok for 2 query parameters but doesn't seem to recognise any more than that?
dGreaves
Gumbo, I think your rule that does the work should have 'L' instead of 'N' and no slash before the $4: `RewriteRule ^([^/]+)/([^/]+)(/(.*))?$ $4?$1=$2 [L,QSA]`
bmb
@bmb: No, is has to be exactly like that.
Gumbo
Gumbo, okay, if you say so. It doesn't work for me.
bmb