I have a PHP file:
example.com/products/index.php
My goal is to able to do this:
example.com/products/186/Hello to you
and in PHP I can do $_GET['id']
which will be 186
,
and $_GET['cat']
which will be "Hello to you".
So far I tried this below, but I get:
You don't have permission to access this resource. Additionally, a 403 Forbidden error was encountered while trying to use an ErrorDocument
Options -MultiViews
RewriteEngine On
# HTTP to HTTPS canonical redirect
RewriteCond %{HTTP_HOST} example\.com [NC]
RewriteCond %{SERVER_PORT} 80
RewriteRule (.*) https://example.com/$1 [R=301,L]
# Abort early if the request already maps to (or looks like) a file or directory
RewriteCond %{REQUEST_URI} \.\w{2,4}$ [OR]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^(products)/([^/]*)/?(.*) $1/index.php?id=$2&cat=$3 [L]
# 3. Extensionless URLs for other requests (this below works fine and is for something else)
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule (.*) $1.php [L]
Your "403 Forbidden" problem is related to a recent update to Apache and the spaces in your requested URL. As discussed in the following question:
RewriteRule ^(products)/([^/]*)/?(.*) $1/index.php?id=$2&cat=$3 [L]
Since you are permitting spaces in the requested URL (encoded as %20
in the request), which you are capturing and passing to the substitution string, you need to include the B
flag in order to URL encode the backreferences.
Try the following instead:
RewriteRule ^(products)/([^/]*)/?(.*) $1/index.php?id=$2&cat=$3 [B,L]
However, your regex (RewriteRule
pattern / 1st argument) would seem too "flexible" as it makes the 3rd path segment optional (ie. a URL of the form /products/anything
would be accepted) - is that intentional?
To match only URLs of the form /products/<id>/<cat>
(where <id>
consists only of the digits 0-9) then your RewriteRule
pattern should be modified to something like the following instead:
^(products)/(\d+)/(.+)
It's mentioned in comments about using $_SERVER['REQUEST_URI']
instead of passing the URL parameters. This is OK, but doesn't save much (if anything) in this instance as this looks like an isolated case and not how the rest of your site is constructed. In this case your rule in .htaccess
would become:
RewriteRule ^(products)/\d+/. $1/index.php [L]
(Aside: Although an added benefit of this approach is that it does naturally prevent the same resource being accessible via a URL of the form index.php?id=<id>&cat=<cat>
, thus avoiding a potential duplicate content issue. An additional rule can be used in .htaccess
to redirect such requests to the canonical URL.)
And in PHP you parse the values directly from the requested URL-path (as stored in the $_SERVER['REQUEST_URI']
superglobal). For example:
<?php
$urlPath = parse_url($_SERVER['REQUEST_URI'],PHP_URL_PATH);
$urlPathParts = explode('/',$urlPath);
$id ??= $urlPathParts[1];
$cat ??= $urlPathParts[2];