How to automatize rewriterule in .htaccess? - php

I'm doing this in .htaccess:
RewriteRule ^([A-Za-z0-9-]+)[/]?$ /index.php?u1=$1 [L,QSA]
RewriteRule ^([A-Za-z0-9-]+)/([A-Za-z0-9-]+)[/]?$ /index.php?u1=$1&u2=$2 [L,QSA]
RewriteRule ^([A-Za-z0-9-]+)/([A-Za-z0-9-]+)/([A-Za-z0-9-]+)[/]?$ /index.php?u1=$1&u2=$2&u3=$3 [L,QSA]
RewriteRule ^([A-Za-z0-9-]+)/([A-Za-z0-9-]+)/([A-Za-z0-9-]+)/([A-Za-z0-9-]+)[/]?$ /index.php?u1=$1&u2=$2&u3=$3&u4=$4 [L,QSA]
Is there any way to make this automatically from u1 to u(infinite), automatically, based on the length of the url, without having to define every case?

No, neither Apache nor regex offer programmatic processing of an unspecified number of arguments. But PHP is designed for such things, so you're best off simply using one rule:
RewriteRule ^([A-Za-z0-9/-]+)$ /index.php?path=$1
Then have your PHP script break the path variable apart by calling the explode function on the forward-slash character. And you'll get an array containing each piece of the full path.
This way your PHP script can handle an unlimited number of path elements, and Apache won't need to wear itself out trying to make sense of infinite regex patterns.

Related

URL rewrite php query strings

I have two urls doing some queries which I'm struggling to rewrite in the manner I want.
First
/shop/index.php?category=catslug
which I want to be
/shop/category
Second
/shop/index.php?product=slug
to
/shop/category/product
I have this currently:
RewriteRule ^shop/([A-Za-z0-9-]+)/?$ shop/index.php?category=$1 [L]
RewriteRule ^shop/[A-Za-z-]+/([A-Za-z0-9-]+)/?$ shop/index.php?product=$1 [NC,L]
The problem is that one of the rules is ruining anything that starts with shop so that things like shop/cart doesn't work. I'm so confused. Is this possible?
Note that for shop/cart, the cart part matches the [A-Za-z0-9-]+ part of the first RewriteRule. So it is rewritten to shop/index.php?category=cart.
The way to avoid this, hoping that you have a relatively small number of fixed URLs, is to have a RewriteRule before your 2 rules like
RewriteRule ^shop/(cart|this|that|other|thing) - [L]
RewriteRule ^shop/([A-Za-z0-9-]+)/?$ shop/index.php?category=$1 [L]
RewriteRule ^shop/[A-Za-z-]+/([A-Za-z0-9-]+)/?$ shop/index.php?product=$1 [NC,L]
For requests matching one of the pipe-delimited strings (such as cart), - means don't change the request, and [L] means last (don't continue to the next rules).

Reoccurring htaccess command

I need to continue this indefinatly in length without writing it out everytime.
Is there a way to achieve this?
RewriteRule ^(\w+)/?$ index.php?page=$1 [QSA]
RewriteRule ^(\w+)/(\w+)/?$ index.php?page=$1&$1=$2 [QSA,L]
RewriteRule ^(\w+)/(\w+)/(\w+)/?$ index.php?page=$1&$1=$2&$2=$3 [QSA,L]
So all the way through $1=$2 then $2=$3 so page=blog&blog=article&article=date&date=2012
My PHP then takes this and runs analysis on this. So could be as as $1 -> $11 Long URL I know means that I can still enable adding.
AAA.com/blog/article/date/2012/?colour=blue
Not as such. To get an replacement $5 placeholder, you do need a match group.
One could of course optionalize it group-wise:
RewriteRule ^(\w+)(?:/(\w+))?(?:/(\w+))?(?:/(\w+))?(?:/(\w+))?(?:/(\w+))?(?:/(\w+))?/?$ index.php?page=$1&$1=$2&$2=$3&$3=$4&$4=$5&$5=$6 [QSA,L]
But then you had a few &=&=&= trailing for absent entries. Usually it should result in an empty $_GET[""], but PHP even ignores that. So, might be an option. I don't feel it's a more readable or concise RewriteRule though.

Passing Variable in html extension pages. like html?a=asdfadf

I want to pass variable in .html extension pages and .html pages are made up of mod rewrite so these are not html files but php script which are made .html through mod rewrite.
any clue?
EDIT: My .htaccess file*:
RewriteEngine on
RewriteRule ^watch/(.*)/(.*).html$ video.php?tag=$1&video=$2 [L]
RewriteRule ^(.*)/([0-9]+).html$ index.php?tag=$1&page=$2 [L]
RewriteRule ^(.*).html?([a-zA-Z=]+)$ index.php?tag=$1 [L]
* As supplied in the comments. Spacing may be different than the original.
Add the [QSA] flag to your rewrites. That will take the original query string and add your new params to it.
RewriteRule ^(.*).html$ index.php?tag=$1 [L,QSA]
This will rewrite whatever.html?orderby=views into index.php?tag=whatever&orderby=views.
The only catch is, with PHP anyway, whatever.html?tag=somethingelse will give you some weirdness. ($_GET['tag'] will have two values, but only the one that shows up last will be the real value.) But that's generally fine; you just have to be sure not to provide URLs like that, and you can just not care what people trying those wacky URLs see. (Assuming, of course, that you validate $_GET['tag'] properly.)

mod_rewrite chaining?

I have a bootstrap php file that I am routing all requests through:
RewriteRule ^(.*)$ index.php?query=$1 [L]
Say I have a url like /books/moby-dick, but I need the URL to pass to the index file like /books/detail/moby-dick. Is there a way to "rewrite" /books/moby-dick to /books/detail/moby-dick before the last RewriteRule? I thought the Chain [C] flag would do it but I end up with "books/detail/moby-dick/moby-dick". Here's where I'm currently stuck:
RewriteRule ^books/([A-Za-z0-9\-]+)$ books/detail/$1 [C]
RewriteRule ^(.*)$ index.php?query=$1 [L]
Any rewrites that you perform will automatically flow down to subsequent rules in your rule set provided that you don't cause the process to end/restart with the L (which typically restarts when used in .htaccess) or N flag. You could remove the chaining and it would still work, although in that case you'd have to condition the second rule:
RewriteRule ^books/([A-Za-z0-9\-]+)$ books/detail/$1
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?query=$1 [L]
Note that if you do chain the rules together, if the request path does not match the first rule, the request won't be redirected to the bootstrap file.
None of that is the cause of the actual problem though. What happens is that Apache has decided that the request has path info (for reasons I'll have to look into), and after your rewrite it automatically appends that to the result. The supposed "path info" is /moby-dick, which is why it ends up appearing twice.
Luckily, since we didn't want it in the first place, we can discard it with the DPI flag. Keeping the above points in mind, the following will redirect a request to books/moby-dick to index.php?query=books/detail/moby-dick:
RewriteRule ^books/([A-Za-z0-9\-]+)$ books/detail/$1 [DPI]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?query=$1 [L]
(I made the assumption you wanted books/detail/name, although you also mentioned books/view/name)
In .htaccess rules (unlike the same rules in httpd.conf) the [L] flag starts all over at the top. You probably really want to use the [END] flag (but only later versions of Apache support it). I believe the reason you get your change repeated has nothing to do with the [C] flag, but rather is because that line is being executed twice. (In fact the only thing that saves you from an "infinite loop" is your "-f" test ultimately stops things).
Each modification in a .htaccess file is always "passed on" to the next line (there are no flags to either enable or disable this behavior). The little-used [C] flag seems to mainly be useful for nested conditionals and for very slight simplification of some awkward if-then-else structures, neither of which you're doing in the example. That's why I don't understand that you need the [C] flag at all.
The standard technique to avoid massive looping and repeating problems in older .htaccess files is to add a bit of boilerplate at the top, something like
RewriteCond %{ENV:REDIRECT_STATUS} !^[ /]*$
RewriteRule ^ - [L]

Recursive mod_rewrite for search engine friendly urls

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?
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).
I understand this is a very old thread. But since none of the answers posted here worked for me and I want to post my answer so that visitors can use it if they want so I am answering it here:
Options +FollowSymlinks -MultiViews
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/([^/]+)(/.*)?$ $3?$1=$2 [N,QSA,DPI]
RewriteRule ^(/[^/]+|[^/]+/|/?)$ /index.php [L,QSA,DPI]
For more details please see my answer on MOD_REWRITE for URL variables, removing empty parameters and using more than 1field for the first and second variables
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.
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.

Categories