skip to Main Content

Bellow is my site directory structure:

htdocs/
    My-Project/
        .htaccess
        public/
            css/
            img/
                img.jpg
            js/
        index.php
        ...(other stuff)

I want to use an .htaccess file to check if the requested path is a file in the public/ directory (similar to serving static files from an directory in express with express.static). If yes, serve it, else forward request to /index.php.

Basically my problem can be split into the following Sub-Problems:

SubProblem1: Serve only files from public directory, else route to index.php
SubProblem2: Serve these files from public directory without (need of) ‘public’ in the URL

So /My-Project/img/img.jpg should be rewritten to /My-Project/public/img/img.jpg but /My-Project/notexisting.file or /My-Project/testshould be rewritten to /My-Project/index.php.

This was my idea so far:

    RewriteEngine On
    
    #Block 1
    #Condition: File exists in public directory
    RewriteCond %{DOCUMENT_ROOT}/My-Project/public/$1 -f
    RewriteRule ^(.*)$ public/$1 [L]

    #Block 2
    #Condition: File doesn't exist in public directory
    RewriteCond %{DOCUMENT_ROOT}/My-Project/public/$1 !-f
    RewriteRule ^(.*)$ index.php [L,QSA]

When Block 1 stands alone -> SubProblem2 is solved, but as soon as Block 2 is added for solving SubProblem1 every Request is rewritten to index.php. Why does that happen? Why doesn’t work the second RewriteCond as expected?

2

Answers


  1. Chosen as BEST ANSWER

    The second RewriteCond didn't work as I expected, because as soon as Block1 rewrites the Request, $1 in Block2 doesn't contain the same Information as in Block1.

    Example

    Imagine we have the URI /My-Project/img/img.jpg.
    In Block1 $1 will be img/img.jpg. Because this file exists, the RewriteCondition would be fulfilled and the new URI will be My-Project/public/img/img.jpg.
    Now it comes to Block2: Because of the rewritten URI, $1 is here defined as public/img/img.jpg. So the RewriteCondition will check, if there is any existing File under the URL MyProject/public/public/img/img.jpg. Of course it isn't. So the RewriteCondition will always be fulfilled and every Request will be rewritten to index.php regardless of any former Rewriting.

    Solution

    RewriteEngine On
    
    RewriteCond %{DOCUMENT_ROOT}/My-Project/public/$1 -f
    RewriteRule ^(.*)$ public/$1 [L]
    
    RewriteCond %{THE_REQUEST} s/My-Project/public/ [NC,OR]
    RewriteCond $1 !^public/
    RewriteRule ^(.*)$ index.php [L]
    

  2. Here’s what I use:

    RewriteEngine On
    
    # The following rule tells Apache that if the requested filename
    # exists, simply serve it.
    
    RewriteCond %{REQUEST_FILENAME} -s [OR]
    RewriteCond %{REQUEST_FILENAME} -l [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^.*$ - [NC,L]
    
    
    # The following rewrites all other queries to index.php. The 
    # condition ensures that if you are using Apache aliases to do
    # mass virtual hosting, the base path will be prepended to 
    # allow proper resolution of the index.php file; it will work
    # in non-aliased environments as well, providing a safe, one-size 
    # fits all solution.
    
    RewriteCond %{REQUEST_URI}::$1 ^(/.+)(.+)::2$
    RewriteRule ^(.*) - [E=BASE:%1]
    RewriteRule ^(.*)$ %{ENV:BASE}index.php [NC,L]
    

    Update My apache vhost configuration if you need it looks like this:

    <VirtualHost *:80>
        ServerName awesome.scot
        ServerAlias localhost
        DocumentRoot /var/www/html/public
    
        <Directory "/var/www/html">
                DirectoryIndex index.php
                FallbackResource /index.php
                Options -Indexes +FollowSymLinks
                AllowOverride FileInfo All
                Require all granted
        </Directory>
        ProxyPassMatch ^/(.*.php)$ fcgi://php:9000/var/www/html/public/$1
    </VirtualHost>
    

    Then in /etc/hosts, I added 127.0.0.1 awesome.scot, so now I access my site in the browser with http://awesome.scot

    Note the two folders in the vhost conf, one is the site root, one is the public directory.

    If you haven’t turned vhosts on, give it a try! Uncomment the vhosts line in your apache conf, then go into the extra folder and configure your vhost, then restart!

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search