Symfony 1.4 on shared webhosting

Some time ago (actually when I was making this blog) I posted on stackoverflow.com a question on how to configure Symfony to run on shared webservers where you can't change your website's document root. I solved it but forgot that I was asking and left it without any answer.

The problem

Symfony framework expects that you can change your website's document_root, so the only accessible part of your site is web directory. It makes perfect sence because the only PHP script accesible from the Internet is just index.php.

Unfortunately, on most webhostings this is imposible. For example in my case, webserver is configured as follows:

/www   => mydomain.com
/foo   => foo.mydomain.com
/bar   => bar.mydomain.com

If I was going to put my Symfony application into /www folder there would be:

/www
/www/apps
/www/apps/frontend
/www/apps/frontend/...
/www/apps/backend
/www/apps/backend/...
/www/cache
/www/config
... and so on...
/www/web

This basicaly means that if I wanted access my website I would have to call mydomain.com/web and that's really uncomfortable.

Rewrite urls

Because I wanted to get rid of that web in all my URLs and of course I wanted to keep all functionality as it is I just slightly modified sfPatternRouting class.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
// apps/frontend/lib/sfPatternRoutingSharedHosting.class.php
class sfPatternRoutingSharedHosting extends sfPatternRouting {

    public function generate($name, $params = array(), $absolute = false) {
        // take the original url
        $url = parent::generate($name, $params, $absolute);
        
        // if we're not in debug environment and url starts with `/web`, then strip it
        if (!$absolute && strpos($url, '/web') === 0 && !sfConfig::get('sf_debug')) {
            return substr($url, 4);
        } elseif ($absolute && strpos($url, '/web/') !== false) {
            return str_replace('/web/', '/', $url);
        }
        return $url;
    }
}

and set our customized class as a routing class.

# apps/frontend/config/factories.yml
all:
  routing:
    class: sfPatternRoutingSharedHosting

Basically, this means that we can use all helpers like `url_for` or `link_to` as we were used to.

.htaccess

Because all URLs are pointing to the /www directory, we need to make rewrite that will internally change every incoming request from http://www.mydomain.com/page to http://www.mydomain.com/web/page.

# Enable rewrite engine and route requests to framework
RewriteEngine On
RewriteBase /       
 
RewriteCond %{REQUEST_URI} ^/robots.txt
RewriteRule ^(.*)$ /web/robots.txt [L]

# resources
RewriteCond %{REQUEST_URI} ^/images/  [OR]
RewriteCond %{REQUEST_URI} ^/js/      [OR]
RewriteCond %{REQUEST_URI} ^/fonts/   [OR]
RewriteCond %{REQUEST_URI} ^/css/
RewriteRule ^(.*)$ /web/$1 [L]

RewriteCond %{REQUEST_URI} !^/web/
RewriteRule ^(.*)$ /web/index.php/$1 [QSA,L]

Directories /images, /js, /fonts and /css are internally redirected to /web/images, /web/js and so on, while all other requests are processed by /web/index.php which is actually Symfony's entry point.

Conclusion

I'm not sure if this is the best solution but I think when you can't change your document_root and you really want to use Symfony there's no better way.

Anyway, keep in mind that you should always double check that configuration files like /config/databases.yml are not accessible from the Internet.

blog comments powered by Disqus