1

I want to convert the following

https://example.com/download-file/xyz
https://example.com/download-code/abc
https://example.com/developer/mno

to

https://example.com/download-file?name=xyz
https://example.com/download-code?name=abc
https://example.com/developer?name=mno

and I would like the param versions to work as well, as they are published.

I tried this, and it works. But it shows the new path in the browser. How can I fix this? And it would be nice to perhaps combine the first two or all 3 into one.

RewriteCond %{HTTP_HOST} ^example.com$ [NC]
RewriteRule ^(download-file)/([^/]+)$ https://example.com/download-file?name=$2 [L]
RewriteCond %{HTTP_HOST} ^example.com$ [NC]
RewriteRule ^(download-code)/([^/]+)$ https://example.com/download-code?name=$2 [L]
RewriteCond %{HTTP_HOST} ^example.com$ [NC]
RewriteRule ^(developer)/([^/]+)$ https://example.com/developer?name=$2 [L]

The only rules before this are

RewriteEngine On

#com
RewriteCond %{HTTPS} =on
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]

RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} ^(www\.)?example\.com$ [NC]
RewriteRule ^(.*)$ https://example.com%{REQUEST_URI} [R=301,L,QSA]

#nz
RewriteCond %{HTTP_HOST} ^(www\.)?example\.nz$ [NC]
RewriteRule ^(.*)$ https://example.com/$1 [R=302,L]

# Rewrite to ".php" then html
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^(?!.+\.\w{2,4})(.+)$ $1.php [L]
RewriteCond %{DOCUMENT_ROOT}/$1.html -f
RewriteRule ^(?!.+\.\w{2,4})(.+)$ $1.html [L]

and the only thing after the rules of concern is gzip and security headers.

Finally, this is the primary domain, so there are no other .htaccess rules in play.

5
  • To be clear, it looks like you want an internal rewrite that sets the handler for the request to a script that accepts a parameter and NOT a redirect (which changes the URL for the user.) Jun 23 at 15:23
  • Your target URLs (eg. https://example.com/download-file?name=xyz) are not the actual end points and require further rewriting in order to "work". So, you must have other directives that do the next step? You should be rewriting to the final end-point in one go in these rules. What are the actual URLs/file-paths that handle the requests? Are these .php files perhaps? Do you need to check the requested host? Are you hosting multiple domains on this one account and these other domains use the same URL-path that should not be rewritten?
    – MrWhite
    Jun 23 at 23:40
  • @StephenOstermiller yes I am trying for internal rewrites. Jun 23 at 23:44
  • @MrWhite, yes the files are PHP and I have subdomains and other domains mapped here too. But I don't need to check the host, because those segments are unique. I wasn't sure what else I could check for? Can I have a rule without a condition? Jun 23 at 23:47
  • I have added the prefix to those rules in my post. And the only suffix is gzip and securtiy headers. And this is the primary domain, so other htaccess files have no effect on this. Jun 23 at 23:58

1 Answer 1

2
RewriteCond %{HTTP_HOST} ^example.com$ [NC]
RewriteRule ^(download-file)/([^/]+)$ https://example.com/download-file?name=$2 [L]

By using an absolute URL (with scheme + hostname) in the substitution string it will implicitly trigger a 302 (temporary) redirect. To "internally redirect" (or "rewrite") the URL you must specify a relative (or root-relative) URL-path (or file-path).

As mentioned in comments, https://example.com/download-file does not appear to be a valid end-point. You've stated these are .php files, which you are currently relying on other rules to perform a second rewrite to append the file extension. You should instead perform this in a single rule/rewrite.

There does not appear to be a need to check the requested hostname since these URLs are unique to a particular hostname. However, since you are hosting multiple hostnames on the same account (in the same file space?) it may be beneficial to check the requested host to avoid accidental duplicate content (due to some other error that might occur in linking). Although if that is not an issue (eg. other hostnames are canonicalised or point to other file-paths) then you can remove the condition that checks the requested hostname.

In the rule above there is no need for the capturing subgroup around the first path segment, eg. (download-file) since this is not being used later and is forcing you to use $2, when $1 is sufficient. However, if you want to combine these 3 rules then you do need the capturing subgroup.

Try the following instead, combining all 3 rules:

RewriteCond %{HTTP_HOST} ^example\.com [NC]
RewriteRule ^(download-file|download-code|developer)/([^/]+)$ $1.php?name=$2 [END]

And this rule should go before the rules that append the .php (and .html) file extensions.

Providing you are on Apache 2.4+, it is more efficient to use the END flag here instead of L, in order to prevent any further looping by the rewrite engine.

The $1 backreference contains the file basename (less the .php extension) and $2 is the URL parameter value, as before.

Disable MultiViews

Note that, since you are rewriting to the same .php file as in the requested URL (just less the .php extension) you need to ensure that MultiViews is disabled for this rule(s) to work. It must already be disabled, otherwise your "redirect" would not have "worked". However, for your code to be portable you should explicitly disable this at the top of your .htaccess file:

# Ensure that MultiViews is disabled
Options -MultiViews
3
  • I've updated my answer to use the END flag instead of L and mentioned that MultiViews should be disabled.
    – MrWhite
    Jun 24 at 0:57
  • That works, I have added the -Multiviews option. The only issue I have is that POV has changed so, all my relative paths to assets no longer work. I had changed them to relative as that made it portable between my dev machine and target. But going forward I want this, so I will rejig my paths. Jun 24 at 1:28
  • @RohitGupta Using relative URL-paths to your static assets will certainly cause problems when rewriting the URL at different path depths. A workaround is to set the base tag in the head section of the HTML (although this does have other caveats). See the following related question: .htaccess rewrite URL leads to missing CSS
    – MrWhite
    Jun 24 at 11:29

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.