1

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]

MrWhite
  • 43,179
  • 8
  • 60
  • 84
Matilda
  • 15
  • 5
  • **Nobody** does it this way. With regular rewrite you always have $_SERVER['REQUEST_URI'], and you can split it using explode(). This is WAY more flexible as it allows any URL format. Don't meddle with .htaccess. Keep it a simple rewrite to index.php and parse all requests in PHP – Your Common Sense May 04 '23 at 18:12
  • @YourCommonSense I heard using server request URI is very unreliable :/ – Matilda May 04 '23 at 18:17
  • Whatever you heard it's 100% wrong. – Your Common Sense May 04 '23 at 18:20
  • After all, in your .htaccess you are using the same REQUEST_URI. If it's "unreliable", then your .htaccess would be unreliable too – Your Common Sense May 04 '23 at 18:32
  • @YourCommonSense The problem is if I "mywebsite.com/products/186/Hello to you", it's not going to use the index.php that's in the PRODUCTS folder. there's only so much I can do in PHP. do you know what I mean? – Matilda May 04 '23 at 18:37

1 Answers1

0

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];
MrWhite
  • 43,179
  • 8
  • 60
  • 84
  • Mr white, as always, you're a genius! – Matilda May 04 '23 at 19:22
  • one question though, when I use code above and go to: products/186 232. I get 404. Because there's a space between 186 and 232. Is this supposed to happen? :/ – Matilda May 04 '23 at 19:24
  • @Matilda So, `186 232` (with a _space_) is the "id"?! And no "cat" parameter? In that case you would need to revert back to using something like your original regex as the `RewriteRule` _pattern_. ie. `^(products)/([^/]*)/?(.*)`. (Which would then rewrite the request to `products/index.php?id=186+232&cat=`.) – MrWhite May 04 '23 at 20:30