简体   繁体   中英

Apache2 .htaccess rewrite rule for nested URLs doesn't work

I have simple php application with navigation based on domain/foo/bar nested urls.

For instance, I have main page index.php with about nav link which should navigate to domain/en/about , where en and about must be transfered to url param like index.php?url=... .

But when I click to about I got to domain/en/about and 404 not found instead.

I have configured apache2 virtual domain config as:

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    <Directory /var/www/html/domain>
         Options -Indexes +FollowSymLinks -MultiViews
         AllowOverride All
         Require all granted
     </Directory>
    DocumentRoot /var/www/domain/   
    ServerName domain.local
    ServerAlias www.domain.local
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

And .htaccess file as:

order deny,allow
RewriteEngine On
RewriteBase /
RewriteRule .* index.php?url=$0 [QSA,L]

mod_rewrite for apache2 is already enabled.

Have no clue what I have missed.

Any help is appreciated! Thank you in advance!

You need parenthesis around what you want to capture. Back-references indices start with '1':

RewriteRule (.*) index.php?url=$1 [L,QSA]
<Directory /var/www/html/domain>: DocumentRoot /var/www/domain/

Your <Directory> section and DocumentRoot directive refer to different locations, so regardless of where you've put the .htaccess file, it's not going to work as intended.

However...

 RewriteRule.* index.php?url=$0 [QSA,L]

This rule is not strictly correct, since it ends up rewriting itself on a second pass by the rewrite engine. If it wasn't for the QSA flag, the original url param value (that contains the originally requested URL-path) would be lost. The above ends up rewriting a request for /en/about to index.php?url=index.php&url=en/about . Fortunately, your PHP script still reads $_GET['url'] as en/about . But you can examine the full (erroneous) query string in $_SERVER['QUERY_STRING'] .

(And, if you were to simply prefix the substitution string with a slash, ie. a URL-path, you'll get an endless rewrite-loop (500 Internal Server Error). But this could also result from adding additional rules later.)

You should prevent requests to index.php itself being rewritten, which you can do by adding an additional rule. For example:

RewriteRule ^index\.php$ - [L]
RewriteRule .* index.php?url=$0 [QSA,L]

However, this will still rewrite your static assets (assuming you are linking to internal images, CSS and JS files?). So, you would normally need to prevent this with an additional condition that prevents the rule from being processed if the request already maps to a static file.

For example:

RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.php?url=$0 [QSA,L]

The CondPattern -f checks if the TestString maps to a file. The ! prefix negates this. So the condition is only successful when the request does not map to a file.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM