Zend Framework on shared hosting

Zend Framework recommends – but does not rigidly enforce – a file structure for your application. Most of the prominent “getting started” sample apps – like the Zend Framework Quickstart, Rob Allen’s Getting Started tutorial, HariKT’s Base Files skeleton – use it:

ZF recommended structure

Using this structure usually requires creating a virtual host pointing to this public folder and then creating the file public/.htaccess that maps all non-file, non-directory requests to the index.php file. You then get to enjoy all the rich, creamy Zend goodness.

But sometimes you are stuck with shared hosting and you can’t always place your other app folders as siblings to your public web root. For example, one prominent web hosting company provides me a web root of the form /usr/www/users/myusername with a home directory of /usr/home/myusername.

So whaddya gonna do?

A Solution – Push Down and Protect

This question has been asked and answered many times, but most of the solutions use either custom plugins or tricky .htaccess rules. There’s nothing wrong with those – and in general, they are proposed by people way smarter than me. So there is an argument for going with the best. As they used to say: “No one ever got fired for buying IBM.”

But there is a simpler way that has worked well for me: depart slightly from the recommended file structure and modify some include paths. I have seen this approach referenced before, in particular by tharkun on Stackoverflow, but I had not seen it written out explicitly. So, I offer it here in the hope that other ZF n00bs like me can benefit from it.

Essentially, I just push all my app folders down into a subfolder of the web root called something like _zf, web protect that _zf folder with a Deny from All in an .htaccess file for the folder, and change a few paths in the index.php entry point.

I presume that the shared hosting offers me a web root folder called public_html.

So, my folder structure looks like this:

ZF application structure for shared hosting

I make sure that the file public_html/_zf/.htaccess prevents any direct web access:

Deny from All

This keeps anyone from viewing any of the non-public app files.

Then we just modify paths in public_html/index.php to point to the _zf folder, as follows:


set_include_path(implode(PATH_SEPARATOR,
    array(
        dirname(__FILE__)  . DIRECTORY_SEPARATOR . '_zf' . DIRECTORY_SEPARATOR . 'library',
        get_include_path(),
    )
));

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

// Everything else is the same as usual. For example, using Zend_Application...

// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));

require_once 'Zend/Application.php';  

$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/application.ini'
);
$application->bootstrap()->run();

And that’s it!

A purely modular app structure can also be handled in this way. For example, you can simply put your modules folder inside your application folder. Since all the logic associated to module routing, module bootstrapping, and module-specific paths already resides within the framework, the setup above still works.

The Downside

There is an insidious down-side to all this. Best practice dictates keeping all those app folders – and especially the config files, rich with passwords and the like – out of the web root. In theory, we have that all handled with the .htaccess Deny on the _zf folder. But it’s a single point of failure. If it fails for some reason – say, the .htaccess file doesn’t get deployed – then we are fully exposed to a wide variety of potential mischief.

There is some additional obscurity you can obtain by changing the name of the _zf folder to something (practically) unguessable. I could even imagine a cron job that renames the folder and makes corresponding changes to the index.php file. But that’s probably excessive. And, in any case, as we should all well know, relying solely on security through obscurity is a poor approach.

But maybe this approach is useful to get an app off the ground with a customer who is stuck with his shared hosting package. At some point in the future, when the app is sufficiently profitable, maybe you can convince the customer to move to virtual private server hosting, at which point it’s a small modification to return to the standard ZF-recommend file structure.

Whaddya think?

10 comments so far »

  1. Andy Thompson said,

    Wrote on May 10, 2010 @ 5:07 am

    Although I don’t use shared hosting, I’d have probably stuck to the standard layout and simply put a .htaccess in the root that rewrote everything to public/$0 as I do on my localhost.

    Of course, as you say, its not hard to change from one system to another, although provided its someone who’s familiar with the framework doing the migration.

  2. david said,

    Wrote on May 10, 2010 @ 10:04 am

    @Andy: Thanks for the visit and the comments.

    Keepng the standard layout and then using an .htaccess to push requests down into public is fine. Still need to put a Deny All on each of the ZF folders (application, library, configs, modules, etc). That’s kind of why I put them all into a single _zf folder. Then I only have a single Deny All on that folder and the access control extends to all the subfolders for free.

  3. Andy Thompson said,

    Wrote on May 10, 2010 @ 2:09 pm

    The root .htaccess rule I mentioned will prevent any of the folders except public/ from being accessed.

    RewriteEngine on
    RewriteRule ^.* /public/$0 [L]

    This will give the effect of moving the web root into public/. e.g. requests to http://domain.com/application/ will actually be served from /public/application/, meaning even those directories are unaccessible.

  4. david said,

    Wrote on May 10, 2010 @ 2:46 pm

    @Andy: Aaah, I think I see what you mean. Since the public folder and the application folder are now siblings, any request for /application will 404 since Apache is trying to serve the non-existent folder public/application. Right?

    But there is a sticky point to this approach. Sure, the user will only see his requested url (say, /mypage) since the rewrite rule only uses the [L] flag and not the [R] flag. But the ZF app itself will see the url that Apache is serving, which is /public/mypage. That means that any defined routes would need to have the ‘public’ prefix in order to be matched. Isn’t that right?

    We could certainly handle those, so it becomes a question of which adjustment (file paths or routes) you want to handle.

    In the end, the conclusion I come to is: shared hosting sucks. ;-)

    Thanks and cheers!

  5. Andy Thompson said,

    Wrote on May 10, 2010 @ 7:44 pm

    @david it’s not a problem if you are dealing with an app at the root level of a website. Zend_Controller_Request_Http will get confused due to the request uri not matching the script path and calculate the base url to be /, so will continue to match routes.

    It would be a problem for apps at a lower level url as you say, as Zend MVC will think the base url is still /, however the base url can be set manually rather than having to change the routes.

    As for the conclusion, I agree :) , although some shared hosting you can just cheakily delete the web root folder and symlink the app’s public folder to its previous location.

  6. david said,

    Wrote on May 11, 2010 @ 1:30 pm

    @Andy: Funny, just the other day I was talking with a friend about testing symlinking on the shared hosting he offers.

    But even in the absence of symlinking, your new info about baseUrl() really seals the deal. I’ll have to check that out.

    Thanks, man!

  7. cuhe said,

    Wrote on July 7, 2010 @ 11:58 pm

    sorry if my English is bad.
    can you help me with .htaccess on my ZendProject,

    I put this code on my folder /root/.htaccess and /root/public/.htaccess

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

    RewriteEngine On
    RewriteRule ^\.htaccess$ – [F]
    RewriteCond %{REQUEST_URI} =”/”
    RewriteRule ^.*$ /public/index.php [NC,L]
    RewriteCond %{REQUEST_URI} !^/public/.*$
    RewriteRule ^(.*)$ /public/$1
    RewriteCond %{REQUEST_FILENAME} -f
    RewriteRule ^.*$ – [NC,L]
    RewriteRule ^public/.*$ /public/index.php [NC,L]

    but my page was not running well, can you help me ?

    bigfull thank’s

  8. david said,

    Wrote on July 8, 2010 @ 12:26 am

    @cuhe: Thanks for the visit and the comment.

    In what way is it not working? Are you getting a 404? Are your images/stylesheets not being found? Is something else happening?

    I confess that I am not expert when it comes to the twisty aspects of RewriteRules. In fact, that’s why I usually avoid some of these solutions and use my own solution, pushing all the ZF content into a protected _zf folder. Then I can use the “standard” .htaccess at the root and only have to protect the _zf folder and change an include path.

    Maybe try posting the question at either zfforums.com or stackoverflow.com. Both those places are populated with people much smarter than me. ;-)

  9. Varun said,

    Wrote on August 20, 2011 @ 4:15 am

    Hats off, sir! In all the .htaccess stupidity all over the place – this was the first legit sensible tutorial that actually made sense AND worked

  10. david said,

    Wrote on August 21, 2011 @ 10:30 am

    Hi @Varun. Thanks for the visit, the comment, and the compliment. Yeah, I found the .htaccess approach to be a bit “tricky” so the “move the whole ZF folder” approach worked for me. Cheers!

One pingback/trackback so far »

  1. Zend Framework News » Blog Archive » Zend Framework auf Shared Host einrichten said,

    Wrote on May 10, 2010 @ 12:10 pm

Leave a Comment

Name: (Required)

E-mail: (Required)

Website:

Comment: