Home > OS >  rewrite request for /folder to folder/index.php without 301 redirect with apache
rewrite request for /folder to folder/index.php without 301 redirect with apache

Time:04-10

So I put an index.php in /pipe/index.php

I'd like to rewrite (internal, not redirect) https://host/pipe?token=abc to https://host/pipe/index.php?token=abc

what I tried (caveat, assumes there is always a ? in the url):

RewriteEngine on
RewriteRule "^([^?]*)(.*)$" "$1/$2" [PT]

my hope was to split at the ? and just insert a / there.

But it seems apache finds out that "oh, pipe is a folder" before checking my .htacces (?) Because despite my [PT] it still redirects with 301 to /pipe/?token=abc, when I hoped for internal rewrite.

CodePudding user response:

This probably is what you are looking for:

RewriteEngine on
RewriteRule ^/?pipe/?$ /pipe/index.php [QSA,L]

The QSA flag is actually redundant here, it is the default, but it makes things clearer if you compare it to that variant (both work):

RewriteEngine on
RewriteRule ^/?pipe/?$ /pipe/index.php?%{QUERY_STRING} [QSD,L]

The documentation of the rewriting module, more specific of the RewriteRule directive clearly points out that the query string is not part of the path the rule's pattern is matched against.

If you want to have more control about the content of the query string you can use a RewriteCond:

RewriteEngine on
RewriteCond %{QUERY_STRING} ^token=(.*)$
RewriteRule ^/?pipe/?$ /pipe/index.php?token=%1 [QSD,L]

Also you might want to redirect the original URL:

RewriteEngine on
RewriteRule ^/?pipe/index.php /pipe [QSA,R=301,END]
RewriteRule ^/?pipe/?$ /pipe/index.php [QSA,L]

And finally you might also want to take a look at the DirectoryIndex directive which might offer a solution without any rewriting at all, though this depends a bit on your setup ...

CodePudding user response:

But it seems apache finds out that "oh, pipe is a folder" before checking my .htacces (?)

Yes, mod_dir will append the trailing slash with a 301 redirect. Although this occurs after mod_rewrite has processed the URL (if indeed it is being processed at all - see below). (The PT flag is irrelevant in .htaccess, since the resulting rewrite is passed through as a URL-path by default.)

RewriteRule "^([^?]*)(.*)$" "$1/$2" [PT]

However, your existing rule (by itself) would result in a rewrite-loop (500 Internal Server Error) since it matches itself and repeatedly appends a slash. If you are seeing a 301 redirect as mentioned above then either this rule is not doing anything (are .htaccess overrides enabled?) or you have a conflict with other rules.

As you've stated, this rule also assumes that the query string (with leading ?) is also matched by the RewriteRule pattern. The RewriteRule directive matches against the URL-path only, not the query string. $2 in the above rule is therefore always empty (unless you have ? in the URL-path, ie. a %-encoded ?).

The query string is contained in its own variable, QUERY_STRING. But you simply want to pass through the same query string, so you don't need to do anything special here, since that happens by default.


Solution

To prevent mod_dir appending the trailing slash, you need to set DirectorySlash Off at the top of the .htaccess file. For example:

# Prevent mod_dir appending the trailing slash
DirectorySlash Off

# Must disable directory listings when "DirectorySlash Off" is set
Options -Indexes

However, you need to then manually append the trailing slash to any directory, where it is omitted, with an internal rewrite to "fix" the URL (and to correctly serve the DirectoryIndex, ie. index.php).

# Ensure DirectoryIndex is set correctly
DirectoryIndex index.php

RewriteEngine On

# Append trailing slash to any directory where it has been omitted
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(. [^/])$ $1/ [L]

The trailing slash on the directory (via the internal rewrite) is required in order to serve the DirectoryIndex document, otherwise, you get a 403 Forbidden, even if the DirectoryIndex document is present.

If the trailing slash is omitted and directory listings (mod_autoindex) are enabled (disabled above) then a directory listing would be generated even if a DirectoryIndex document is present in that directory. (Which is why directory listings must be disabled when DirectorySlash Off is set.)

NB: You will need to make sure the browser cache is cleared since the earlier 301 redirect by mod_dir to append the trailing slash will have been cached by the browser.

  • Related