This "doesn't work" in your example because of path-info (additional pathname information) on the originally requested URL. Apache mod_rewrite appends this path-info after the rewrite which conflicts with the later rewrite to replace the .html
extension with .php
.
When you request /pl/index.html
, where /pl
does not exist as a physical directory then the URL-path that follows, ie. /index.html
is path-info. This path-info is re-appended after the first rewrite.
For example, given a request for /pl/index.html
:
RewriteRule ^pl/(.*) public/$1
- this rewrites the request to public/index.html
.
- mod_rewrite then appends the path-info from the original request to become
public/index.html/index.html
.
RewriteRule (.+)\.html$ $1.php [L]
- This directive is now matching against public/index.html/index.html
, which results in the request being rewritten to public/index.html/index.php
- which is not the intention and most probably results in a 404 (unless public/index.html
exists and AcceptPathInfo On
is set).
There are three ways you can resolve this, either:
Add the L
flag to the initial RewriteRule
:
RewriteRule ^pl/(.*) public/$1 [L]
This might seem counterintuitive as you still want the later RewriteRule
to change the file extension - but it still does. The L
flag does not stop all processing, it only stops the current round of mod_rewrite processing and (in a directory context) causes the rewrite engine to start over. Part of the process of "starting over" is that the newly rewritten request is remapped to the file system (and path-info is recalculated), so the later RewriteRule
to replace the .html
extension is applied to the rewritten URL as expected (since no other rewrites occur in the meantime).
The rewrite process loops in this way until the URL passes through unchanged. (Or, the END
flag (Apache 2.4) is encountered.)
OR
Add the DPI
(Discard Path-Info) flag to the initial RewriteRule
instead:
RewriteRule ^pl/(.*) public/$1 [DPI]
This discards the path-info from the current rewrite (and all future rewrites) thus preventing the path-info (ie. /index.html
in this case) from being reappended.
OR
Change the pattern in the last RewriteRule
(that replaces the .html
file extension) so that it matches the first .html
file extension, and not the last file extension. So as to avoid matching against the appended path-info (if present). For example:
RewriteRule ^(.+?)\.html $1.php [L]
Note the trailing $
(end-of-string) anchor on the RewriteRule
pattern is removed and the captured subpattern is made non-greedy (.+?
) so as to match the part of the URL-path before the first .html
and not the last .html
. Any additional path-info (if any) - is also discarded by the rewrite.
Which method to choose?
Instinctively, I would simply add the L
flag. However, adding the DPI
flag instead may in fact be more optimal (it prevents the unnecessary additional loop by the rewrite engine). However, if you add the DPI
flag I would consider reordering (and grouping) the rules to make it more obvious/readable that it is the intention that the URL could be further rewritten for these requests. (It looks like you would need to apply this same process to two other rules as well?)
The third option to change the pattern in the last RewriteRule
feels a bit hacky and I imagine could potentially encounter edge cases that break depending on your URL structure. Although this could still work OK. (Again, reordering of the rules to make the intention more obvious is recommended.)
For example:
RewriteEngine on
RewriteRule ^dekoracyjne.html$ decorative.php [NC,L]
RewriteRule ^techniczne.html$ architectural.php [NC,L]
RewriteRule ^show.html/([-\w]+)$ show.php?id=${products:$1} [L]
RewriteRule ^p.html$ product_configurator.php [NC,L]
RewriteRule ^show_c\.html/([-*\w]+)$ show_c.php?cat=${catcolors:$1} [L]
RewriteRule ^(product_configurator)\.html/(\d+)&([-\w]+)$ $1.php?prometheus_id=$2&id=${products:$3} [L]
RewriteRule ^(ss_c)\.html/(\d+)&([-\w]+)$ $1.php?prometheus_id=$2&id=${products:$3} [L]
RewriteRule ^pl/(.*) public/$1 [DPI]
RewriteRule ^dekoracyjne/(.*) decorative/$1 [DPI]
RewriteRule ^techniczne/(.*) architectural/$1 [DPI]
# Rewrite other ".html" requests to ".php"
RewriteRule (.+)\.html$ $1.php [L]
Aside: You've included the NC
flag on two of the rewrites. This naturally makes the initial match case-insensitive - which shouldn't be necessary. If this is required then you potentially have a duplicate content issue, since foo.html
is strictly different to FOO.html
.
/public/
URLs to redirect or are you expecting that he/pl/
URLs show the same content as the/public/
URLs?[L]
) on that rule because you are expecting the html files in the/public/
directory to get further rewritten from.html
to.php
?cleoni.com/public/
yespl
likepublic
/public/
are rewrite fromphp
tohtml