How the generator builds the rule
The tool splits your example into a script path and a list of parameters. For https://example.com/product.php?id=123&category=shoes the script is product.php and the parameters are id and category. Each parameter becomes one path segment after the prefix, in the order the pills show, so the clean form is /product/123/shoes and the pattern is ^product/([0-9]+)/([^/]+)/?$. The trailing /? accepts the path with or without a final slash.
The target reuses the captured groups: product.php?id=$1&category=$2. Nothing about your application changes. PHP still reads $_GET['id'], and a script in a subfolder such as shop/item.php keeps its folder in the target. If the example has no query string, the tool stops and says there are no parameters to turn into a path.
What the three outputs contain
The Apache block starts with RewriteEngine On, then RewriteRule ^product/([0-9]+)/([^/]+)/?$ product.php?id=$1&category=$2 [L,QSA]. L stops rule processing at this match. The pattern has no leading slash because Apache strips the directory prefix before matching in .htaccess. In a virtual host file the same rule needs ^/product/ instead.
The Nginx block is a location / containing rewrite ^/product/([0-9]+)/([^/]+)/?$ /product.php?id=$1&category=$2 last. Here the leading slash is required, and last makes Nginx search its locations again with the rewritten URI so the PHP location picks it up. The IIS block is a rule element for the rules section of web.config, with a match on the same pattern and a Rewrite action whose back-references are written {R:1} and {R:2}; each ampersand is escaped as & because web.config is XML.
The 301 from old URLs and why it reads THE_REQUEST
Once clean URLs work, the old query-string addresses still work too, and search engines see two addresses for one page. The optional redirect fixes that. It adds RewriteCond %{THE_REQUEST} \s/product\.php\?id=([^&\s]+)&category=([^&\s]+)\s [NC] followed by RewriteRule ^ /product/%1/%2? [R=301,L]. The %1 and %2 come from the condition, and the question mark at the end of the target drops the old query string.
THE_REQUEST holds the request line exactly as the browser sent it, for example GET /product.php?id=123&category=shoes HTTP/1.1. The internal rewrite never changes it, so the condition is true only for someone who asked for the old form. A test on QUERY_STRING would also match the rewritten request and loop.
The condition is literal about shape. It expects the parameters in the order shown, with nothing after them, so product.php?category=shoes&id=123 or a URL with a third parameter is served as before, without a redirect. For Nginx and IIS you have to write the equivalent redirect yourself.
Why a rewritten page loads without styles
The usual surprise after switching is a page with no CSS or images. The browser resolves relative paths against the URL it sees, so on /product/123/shoes a reference to css/site.css becomes /product/123/css/site.css, which does not exist. Use root-relative paths (/css/site.css) in templates, or set a base element in the head.
A 404 on the clean path usually means the rule is not being read. On Apache, check that mod_rewrite is loaded and that AllowOverride permits FileInfo for the directory. Otherwise .htaccess is ignored. On IIS, a 500.19 configuration error after adding the rule is the standard sign that the URL Rewrite module is not installed.
- Parameters arrive empty on Apache when the prefix equals the script name (product and product.php): MultiViews answered first, so add Options -MultiViews.
- Values containing a slash never match ([^/]+). Keep slashes out of anything that goes into the path.
- The generator does not edit your pages: change internal links to the clean form so visitors skip the redirect.
Limits and neighbouring tools
The rules come from one example and are not tested against your server. Every parameter must be present in every clean URL, in the same order. An optional parameter needs a second rule with fewer segments. Text values are matched loosely, so /product/123/anything reaches the script, which should validate its input and answer unknown items with a real 404 so search engines do not index empty pages.
Everything runs in your browser and the example URL is not sent anywhere. For moving pages, forcing HTTPS or removing www, use .htaccess Redirect Generator. After the switch, run Broken Link Checker on your busiest pages: links that now pass through the 301 show up as redirected.