1

There is a PHP script which evaluates one or two parameters via QUERY_STRING. This script should process the parameters via QUERY_PATH. The PHP file type should be omitted.

Request of the form https://example.org/script.php?bla,1 should be converted to https://example.org/script/bla/1.

I think the first part can be accomplished by using

RewriteCond %{REQUEST_URI} ^/script\.php$
RewriteCond %{QUERY_STRING} ^(\w+)(?:,(\w+))?$
RewriteRule .* /script/%1/%2? [R=301,L]

What must be done so that the script without file extension processes the forwarded request? I've tried Multiviews and ForceType - but to no avail.

It is an Apache installation version 2.4. The PHP interpreter runs in CGI mode. There is only access to the .htaccess configuration.

  • 1
    "This script should process the parameters via QUERY_PATH." - Do you mean QUERY_STRING? From your regex, it looks like the ,1 part is optional - is that correct? Presumably you have already converted any internal links to use the /script/bla/1 URL form? – MrWhite Jan 3 at 15:04
  • @MrWhite Thank you for clarifying my request. Yes, I mean QUERY_PATH and yes, the second part is optional. All internal links are generated by a script. So it's just a question of the PHP code. – Denis Giffeler Jan 4 at 18:02
2

This assumes you have already changed any internal links to use the "new" URL of the form /script/bla/1. (Otherwise, you will still be exposing the "old" URL containing the query string and create unnecessary redirects for users and duplicate requests to your site.)

Part One

External redirect from https://example.org/script.php?bla,1 to https://example.org/script/bla/1.

RewriteCond %{REQUEST_URI} ^/script\.php$
RewriteCond %{QUERY_STRING} ^(\w+)(?:,(\w+))?$
RewriteRule .* /script/%1/%2? [R=301,L]

Almost, except you will need an additional condition to prevent a redirect loop (for what we are going to do in the second part to rewrite the URL back to the actual filesystem path). We only want to redirect direct requests, not rewritten requests. We can do this by checking against the REDIRECT_STATUS environment variable, which is empty on direct requests (and set to "200" after the first successful rewrite).

It is also more efficient to check the URL-path in the RewriteRule pattern, rather than using an additional condition that checks against the REQUEST_URI server variable.

So, bringing this together we have...

RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^(\w+)(?:,(\w+))?$
RewriteRule ^script\.php$ /script/%1/%2 [QSD,R=302,L]

Note that a trailing slash will be present if the value after the , (2nd parameter) is omitted.

If you are on Apache 2.4 then you can use the QSD flag instead of appending ? to the substitution. This is preferable (for future development) as there are certain edge cases can result in a different response when simply appending ?.

Test with a 302 (temporary) redirect and only change to a 301 once you have confirmed it works OK (to avoid caching issues).

Part Two

Internal rewrite from https://example.org/script/bla/1 back to https://example.org/script.php?bla,1 (the underlying filesystem path).

I've tried Multiviews and ForceType - but to no avail.

MultiViews will conflict with mod_rewrite in this instance. It will rewrite script to script.php, but without the query string.

You can do something like the following:

RewriteRule ^script/(\w+)/(\w*)$ /script.php?$1,$2 [L]

Note the absence of the R (redirect) flag. Providing you don't include a scheme+hostname then this will result in an internal rewrite - internal to the server, no external redirect.

Note also that the trailing slash, when the "2nd parameter" is omitted, is required. This matches the earlier directive that will always redirect to a trailing slash when the "2nd parameter" is omitted. This will only be an issue if your internal links do not include a trailing slash in such cases.

MultiViews needs to be disabled for this to work. It is not enabled by default on Apache, however, some shared hosts do enable this for some reason.

In Summary

Bringing this together we have:

Options +FollowSymlinks -MultiViews

RewriteEngine On

# Redirect "ugly" URL to "pretty" URL
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^(\w+)(?:,(\w+))?$
RewriteRule ^script\.php$ /script/%1/%2 [QSD,R=302,L]

# Rewrite "pretty" URL back to "ugly" (real) URL
RewriteRule ^script/(\w+)/(\w*)$ /script.php?$1,$2 [L]
  • 1
    I have implemented everything as described - it works wonderfully! Especially interesting for me was the reference to the internal redirection. Many Thanks! – Denis Giffeler Jan 4 at 18:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.