Zend Framework on a shared host

When you deploy a Zend Framework website to a shared host, you usually cannot change the DocumentRoot to point at the public/ folder of the website. As a result the URL to the website is now http://www.example.com/public/. This doesn't look very professional, so we'd like to remove it.

The easiest way, given a ZF project created using Zend_Tool is this:

Create /index.php

<?php 
define('RUNNING_FROM_ROOT'true);
include 'public/index.php';

This uses the index.php already created by Zend_Tool and means that we don't have to change anything if we move to a VPS host where we can set the DocumentRoot directly to public/.

Create /.htaccess


SetEnv APPLICATION_ENV development

RewriteEngine On
RewriteRule .* index.php

We create a .htaccess file that redirects every request to index.php. We want to do this so that no one can try and read application/configs/application.ini. Obviously, set the APPLICATION_ENV to the correct value!

Referencing public facing files

Having created a very aggressive, rewrite rule, what about CSS/JS/image files though?

Fortunately, we already have a .htaccess file in the public/ folder that correctly handles this situation. As Apache will execute the .htaccess files in the deepest directory it finds, any reference to a public facing file within the public/ folder will correctly be served.

You do have to be aware of this when referencing public facing files though and add the /public to the baseUrl yourself.

For example, you may set up your CSS file and other view settings within a Front Controller plugin like this:


class App_Controller_Plugin_View extends Zend_Controller_Plugin_Abstract
{
    public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
    {
        $frontController Zend_Controller_Front::getInstance();
        $view $frontController->getParam('bootstrap')->getResource('view'); 

        $view->doctype('XHTML1_STRICT');
            
        $baseUrl $request->getBaseUrl();
        if (defined('RUNNING_FROM_ROOT')) {
            $baseUrl .= '/public'; 
        }
        $view->headLink()->appendStylesheet($baseUrl '/css/main.css');
        $view->headLink()->appendStylesheet($baseUrl '/css/screen.css''screen');
        $view->headLink()->appendStylesheet($baseUrl '/css/print.css''print');
    }   
}

(This code assumes you have added a resources.view[] = "" to your application.ini)

As we have a constant that tells us if we're running from the root, we can dynamically add the /public into the URL. If we change to a host where the DocumentRoot is set directly to the public/ folder, then we don't need to change our code.

That's it. Your Zend Framework application works nicely with shared hosts.

29 Responses to “Zend Framework on a shared host”

  1. 1 e.s.t

    Thanks, very helpful!
    But still, why use XHTML??:

    http://www.456bereastreet.com/archive/200501/the_perils_of_using_xhtml_properly/

    http://www.webdevout.net/articles/beware-of-xhtml

    http://www.sitepoint.com/forums/showthread.php?t=393445

  2. 2 Nikolaos Dimopoulos

    Thank you for sharing Rob.

    This was something that I was thinking of tackling in the the future but you did all the hard work for me :)

    Thanks again!

  3. 3 Fernando

    Where is $request defined because in a line you have $baseUrl = $request->getBaseUrl();
    but $request doesn't exist at that moment.

    Thanks!!

  4. 4 Lorenzo Alberton

    Last year I wrote an article on how to do it with a slightly different .htaccess file, without touching the PHP scripts:

    http://www.alberton.info/zend_framework_mod_rewrite_shared_hosting.html

    HTH

  5. 5 Rob...

    Fernando,

    $request is passed in as a parameter to dispatchLoopStartup()

    Lorenzo,

    That's an nice solution :)

    Regards,

    Rob...

  6. 6 Steve

    Hi Rob,

    Why not just rename public to public_html and it just works out of the box?

  7. 7 Rob...

    Steve,

    Surely that depends on the shared host?

    Rob...

  8. 8 Steve

    Rob,

    What I mean is, whatever the public folder of the hosts is, so for example in your actual zf app, name the "public" folder, public_html or httpdocs, etc, instead of going with the name public, which is the default.

    Steve

  9. 9 Rob...

    Steve,

    That only works on shared hosts where you are able to store files above publicly accessible folder.

    Rob...

  10. 10 Steve

    Rob,

    Thanks for the clarification. Not all shared hosts impose this restriction. We use Heart Internet at work and we can store the application folders, etc, above public_html.

    Good to know, thanks!

    Steve

  11. 11 haaik

    this is wonderful tutorial .. i read it 2 times and get a fantastic results and sure i put a
    copy of this lesson on my site here

    http://www.haaik.com/vb

  12. 12 Jamie Krasnoo

    Great tutorial. Not all hosts have this restriction though. Most hosts that I know use cPanel which allows you to store the application folders in the main directory above public_html.

    Most hosts using cPanel don't change the name of the document root and leave the default on.

  13. 13 Mary

    My shared host does not have this problem, but it does not over memcache or similar. This means that Zend_Cache does not work as well.

    Can you write a post about your point of view of using Zend_Cache on a shared host without MemCache?

  14. 14 Michal Lasak

    I think, the simplest solution is using the following .htaccess file in ROOT directory.

    RewriteEngine On
    RewriteRule ^(.*)$ public/$1 [L,QSA]

  15. 15 Rob...

    Michal,

    That's certainly simple :)

    Rob...

  16. 16 Bonaparte

    @Mary, if your hosting provider does not offer memcached or apc, you could use the file system for caching.

    You can choose the 'File' backend when instantiating the cache object.

  17. 17 James Dunmore

    Nice post.

    Although I would say that htaccess can be disabled as well - not to mention that they are a performance hit (over apache conf files).

    Just a quick question - do you know how to make zend tool use something other than public? i.e. I want to use public_html, or "web" (i.e. something other, so that I can use existing web roots, etc.) - other than symlinking the directories....?

    Thanks.

  18. 18 Rob...

    James,

    You can call your public folder whatever you like; Zend Framework doesn't care.

    Regards,

    Rob...

  19. 19 James Dunmore

    ZF doesn't care, I know that - but using zend tool - create a project, it names it public - how do you change the defaults on that? It's probably obvious, but I can't seem to find it.

    Cheers.

  20. 20 Daniel Del Rio

    Awesome solution! I really like the other two posted by Lorenzo Alberton and Michal Lasak. I came up with my own solution to this one time using only mod_rewrite rules but it was nowhere as elegant as Michal's solution. Thanks for the article Rob and thanks everyone else for the comments.

  21. 21 Daniel Del Rio

    I just wanted to add that on GoDaddy and maybe some other shared hosts you need to add to the top of the .htaccess file generated by Zend_Tool the following:

    Options -MultiViews

    I'm not sure why this is needed; if someone else knows please explain.

  22. 22 Mary

    Eww GoDaddy, eww cooties

  23. 23 ron

    hi
    did anybody tried this approach on godaddy?
    i have a site ready to be uploaded to my domain on godaddy and i`m not sure how to do it.

    i will appreciate any detailed help.

    best regards

  24. 24 Nikolay Georgiev

    Hi Rob very useful solution for shared hosting. I modified the plgin a bit:
    class App_Plugin_BaseUrl extends Zend_Controller_Plugin_Abstract
    {
    public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
    {
    $frontController = Zend_Controller_Front::getInstance();
    $baseUrl = $request->getBaseUrl();
    if (defined('RUNNING_FROM_ROOT')) {
    $baseUrl .= '/public';
    $frontController->setBaseUrl($baseUrl);
    }

    }
    }

  25. 25 Edvin Seferovic

    Please be advised that setting an environment variable in .htaccess like

    SetEnv APPLICATION_ENV development

    will not work if you are on a shared host which is running PHP as CGI ( probably FastCGI with suExec ).

    Here is a good explanation ( although in german ) http://www.zfforum.de/showthread.php?t=4822 !

    Anyhow - good plugin Rob !

    Kind regards,
    E:S

  26. 26 ron

    hi

    i get the css files and images but all links are not working.

    i have this link: <a href="/bloging/css/index"
    it works great on my local site but on the live site it does not work. it just sends me back to index, even though the url say the right url.

    what am i missing here? please help

  27. 27 Royston Olivera

    just hosted my site built on ZF yesterday on godaddy ... I did fear this issue as i had never done the ZF setup on a shared server earlier and i did not find this article

    so i tried out something different that worked

    My folder structure is now
    public/
    application/
    cache/
    library/
    images/
    css/
    .
    .
    .
    and edited this in my index.php

    set_include_path(implode(PATH_SEPARATOR, array(
    realpath(dirname(__FILE__) . '/library'),
    get_include_path(),
    )));

    // Define path to application directory
    defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/application'));

    This worked for me and my site is live and running. Let me know if there are any problems with this folder structure

  28. 28 KARL

    Rob & Michal, this works perfectly for IIS (in development anyway). Thank you.

  29. 29 Royston Olivera

    just a correction to my comment

    application/
    cache/
    library/
    images/
    css/

    are inside /public

The views expressed in these comments are not the views of the publisher. However, we believe in the rights of others to express their legitimate views and concerns. Any legitimate complaint emailed to rob@akrabat.com will be seriously considered and the post reviewed as desirable and necessary.

Leave a Reply

Buy now!