Search code examples
apachemod-rewrite

Apache mod_rewrite works in .htaccess but not in apache conf file


What I can do in .htaccess is take example.com/s1/s2/s3 and have these as 3 elements in the $_REQUEST array in php. How do I translate this to work correctly in the conf file?

.htaccess

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php [NC,L,QSA]

conf

<IfModule mod_ssl.c>
<VirtualHost *:443>
        DocumentRoot "/home/...path.../public"
        ServerName example.com
        Alias /lib /home/...path.../otherlib/
        <Directory />
                Options Indexes FollowSymLinks
                AllowOverride All
                Require all granted
        </Directory>
        RewriteEngine on
        RewriteCond %{REQUEST_URI} !^/lib/ [NC]
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^(.*)$ /index.php [NC,L,QSA]
</VirtualHost>
</IfModule>

Solution

  • RewriteEngine on
    RewriteCond %{REQUEST_URI} !^/lib/ [NC]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ /index.php [NC,L,QSA]
    

    When used in a virtualhost context, mod_rewrite is processed much earlier, before the request has been mapped to the filesystem. Consequently REQUEST_FILENAME does not yet contain the full filesystem path that the requested URL maps to, it contains just the root-relative URL (the same as REQUEST_URI). So, these two negated conditions will always be successful. (So all your static assets will be rewritten to the front-controller as well.)

    You need to either, use a lookahead, eg. %{LA-U:REQUEST_FILENAME} or construct the filename from the DOCUMENT_ROOT and REQUEST_URI server variables, which works in either context. For example:

    RewriteCond %{REQUEST_URI} !^/lib/ [NC]
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d
    RewriteRule ^/. /index.php [L]
    

    I also simplified the RewriteRule pattern, since there's no need to capture the URL-path here, or match the root directory. The NC and QSA flags are also unnecessary.


    What I can do in .htaccess is take example.com/s1/s2/s3 and have these as 3 elements in the $_REQUEST array in php.

    However, the above does not do this. With the above directives you can access the entire URL from the single $_SERVER['REQUEST_URI'] superglobal element in PHP, which you then need to parse/explode to extract s1, s2 and s3.

    If you specifically wanted 3 elements in the $_REQUEST array then you would need to change the RewriteRule directive to something like the following instead:

    :
    RewriteRule ^/([^/]+)/([^/]+)/([^/]+)$ /index.php?s1=$1&s2=$2&s3=$3 [L]
    

    But that only matches URLs of the form /foo/bar/baz. A two-path-segment URL like /foo/bar would not be matched.