Two (or more) Zend Framework projects on a shared host

Shared hosting environments can be a nightmare when it comes to PHP Web Development, specially in testing stages. Yes, I know one should not be using and paying for a hosting plan if the code is still not production ready, but I have seen some cases.

I will try to show how to have the Zend Framework installed with as many projects as you want (if your server quota allows you to) in the same web space and all these projects sharing the same ZF copy.

Suppose that your home directory is /home/mauricio/. From now on, I am going to refer to it as <root>. Create the following file structure under it:

library/
  Zend/
myfirstproject/
  application/
    controllers/
    views/
      scripts/
mysecondproject/
  application/
    controllers/
    views/
      scripts/
public_html/
  myfirstproject/
  mysecondproject/

Now download, extract and upload the “Zend” directory contained in the zip or gz file into the “<root>/library” directory of the structure that you have just created. This copy of the Zend Framework will be shared by all projects. If needed, you can upgrade to a future version of ZF just by changing its content.

Keep in mind that this example is based on the fact that the public folder on the hosting environment is “<root>/public_html”. Some providers call it “www”, so… in this example our public folder will be called “public_html”, make the appropriate changes to suit your needs.

The first folders: “myfirstproject” and “mysecondproject” will contain the application files that won’t be visible to the outside world. Notice that under public_html exist another two folders under the same names, these two folder will contain the bootstrap or the entry point for the application which must be of public access and all the images, style sheets and other media that your application requires.

Your .htaccess file under <root>/public_html/myfirstproject/ should look like this:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

And the bootstrap file index.php under the same location, should look like this:

<?php
/**
* <root>/public_html/myfirstproject/index.php
*
*/

// The library folder contains Zend Framework files
define('LIBRARY_PATH',     realpath(dirname(__FILE__) . '/../../library/'));
define('APP_PATH',         realpath(dirname(__FILE__) . '/../../myfirstproject/application/'));
define('CONTROLLERS_PATH', APP_PATH . '/controllers/');

// library is appended to the include_path
set_include_path(get_include_path() . PATH_SEPARATOR . LIBRARY_PATH);
include_once 'Zend/Loader.php';
Zend_Loader::registerAutoload();

/**
* The most important step is to set the controllers directory pointing to
* <root>/myfirstproject/application/controllers
*/
$front = Zend_Controller_Front::getInstance();
$front->setControllerDirectory(CONTROLLERS_PATH);
$front->dispatch();

That was the trick, let’s finish this creating our IndexController and its view. The first one should be placed on <root>/myfirsproject/application/controllers/IndexController.php:

<?php

/**
* <root>/myfirstproject/application/controllers/IndexController.php
*
*/
class IndexController extends Zend_Controller_Action
{
  public function indexAction()
  {
  }
}

The view should be anything you like, my bet is for:

<!-- <root>/myfirstproject/application/views/scripts/index.phtml -->
<html>

<head><title>It works!</title></head>

<body>
<h2>It works!</h2>
</body>
</html>

That’s all, you can start building more views, controllers and helpers. To get your second project working just follow the same steps that you did for “myfirstproject” folder. The same way, you can create as many projects as you want, keep in mind that they all share the same Zend Framework library.

24 thoughts on “Two (or more) Zend Framework projects on a shared host

  1. Aaron

    Great article.

    If one has shell access to a host (through a provider like Slicehost), may I suggest that an easier alternative would be to create a symbolic link to a common ZF folder. For instance, assuming the following directory structure under /var/www (or wherever your files exist):

    /var/www/zf-1.7.7
    /var/www/project1
    /var/www/project2

    …it is trivial to go into each project’s Library (e.g., cd /var/www/project1/library) folder and do the following:

    ln -s /var/www/zf-1.7.7 Zend

    Now, whenever a new version of the framework is released, all you have to do is add the new files into that zf-1.x.x folder.

    Reply
  2. Giorgio Sironi

    I prefer single copies of library folder… That makes possible indipendente upgrading and indipendent patching, as not all of the projects would want to upgrade the version of zf at the same time (for example after upgrading I have to run unit and integration tests, and so I can do this on a per-project basis).

    Reply
  3. Ashley Kitson

    I do things slightly differently. I have the ZF framework , Smarty and our own CMS framework (based on ZF of course) in a separate library well outside of web root.
    In my boostrap I do:

    //Define the library path
    define(“LIB_PATH”,DIRECTORY_SEPARATOR . “usr” . DIRECTORY_SEPARATOR
    . “local” . DIRECTORY_SEPARATOR .”Frameworks” . DIRECTORY_SEPARATOR. “lib”);
    //modify include path – add library root path – needs to be hard coded
    ini_set(‘include_path’,ini_get(‘include_path’) . PATH_SEPARATOR . LIB_PATH);
    //find web root path
    $root = dirname(dirname(realpath(__FILE__)));
    define(“ROOT_PATH”, $root);
    require_once ‘Zend/Loader.php’;
    Zend_Loader::registerAutoload();

    Zend Framework is stored in /usr/local/Frameworks/lib/Zend
    Smarty gets stored in /usr/local/Frameworks/lib/Smarty
    Our framework in /usr/local/Frameworks/lib/Ourfw

    on so on.

    The Zend_Loader takes care of everything and by using the ROOT_PATH constant you can add controller and model paths etc at will. Each application then sits in its own vhost on the server using the standard ZF layout

    httpdocs -> public files including index.php, js, css etc
    application -> config, modules, language, cache etc
    modules -> controller, model, view, language

    Works a treat for us and supports myriad sites. Hope it helps others.

    Reply
  4. Mauricio Cuenca Post author

    @Aaron: symbolic links are a great option, it may cause a little bit of overhead on older filesystems and its better to avoid them if performance is a concern.

    @Giorgio Sironi: in terms of portability and backwards compatibility, carrying the whole library on each project is a good approach. Each case has its ups and downs.

    @Ashley Kitson: thanks for the tip! The only problem with it is that you need root access to the server, in my case I’m trying to deal with shared hosts, where your ability to control stuff is limited.

    Reply
  5. Tibo Beijen

    Like aaron I was thinking about symlinks but the overhead mentioned is a good point. A setup like this might also be applicable on a company owned dedicated server that hosts a lot of (smallish) website. As the number of projects increases it becomes increasingly important that not all application neccessarily share the same library version.

    I would suggest (as an extension to the layout in the article) something like this:

    /sharedlib/zend/1.7.0/Zend
    /sharedlib/zend/1.7.7/Zend

    Per application you can then point your include-path to the right version. (In theory the additional Zend folder wouldn’t be neccessary but Zend_Loader likes it very much)

    Reply
  6. Ashley Kitson

    @Mauricio Cuenca – perhaps you could try the approach of setting up a dummy website and use that to store all your libraries, then point your library path at that.

    @Tibo Beijen – I actually think it is very important that all sites share the same version of base libraries. You wouldn’t run different sites on different versions of PHP unless absolutely necessary, so why do it with framework code? If you need to vary stuff, subclass it in your application. We are lucky enough to have a full dev -> test -> production staging setup, so we can run tests before deploying upgrades to the various libraries. The reality with ZF (in our experience) is that new versions of the library rarely break anything and when they are likely to, the ZF team do give notice in the release notes. They maintain backward compatibility very well. Just my opinion and not necessarily correct for all scenarios ;-)

    Reply
  7. Pingback: Mauricio Cuenca’s Blog: Two (or more) Zend Framework projects on a shared host | Development Blog With Code Updates : Developercast.com

  8. Pingback: Mauricio Cuenca’s Blog: Two (or more) Zend Framework projects on a shared host : WebNetiques, LLC : Website Developers in Minneapolis, MN

  9. Pingback: Mauricio Cuenca’s Blog: Two (or more) Zend Framework projects on a shared host : Dragonfly Networks

  10. Pingback: links for 2009-03-27 « sySolution

  11. Pingback: ??????? » [Web] ????

  12. Guillermo

    Mauricio, gracias por el articulo. Tengo la estructura de directorios que mencionas en el blog y me funciona correctamente con dos proyectos diferentes, pero en los dos quiero hacer una pagina de login. Queria saber como puedo hacer con Zend_Auth que en cada proyecto tenga una sesion diferente. Mi problema esta en que si me logueo en un proyecto despues si quiero ir al otro no me aparece la pagina de login, sino que entra directamente.

    Gracias!

    Reply
  13. Mauricio Cuenca Post author

    Hello Guillermo, aunque lo del Zend_Auth no tiene nada que ver con esto. Puedes cambiar el nombre de la sesión en cada instancia propia del módulo que autentica, sería algo como esto:

    $firstengine = new Zend_Auth_Storage_Session(‘ModueloA’);
    $authorize = Zend_Auth::getInstance();
    $authorize->setStorage($firstengine);

    Igual haces para el otro, cada uno con un nombre de sesión diferente, como ‘ModuloB’. Así serán autenticadores independientes y el uno no interferirá con el otro.

    Reply
  14. Marco

    Hi Mauricio
    great tutorial, thank you, I followed it, and it works, except that I get an error if I put index.phtml in /application/views/scripts/
    it works only if a put index.phtml in /application/views/scripts/index/

    Reply
  15. Carlos Andres

    Mauricio, mil gracias por el aporte. Tengo la siguiente inquietud: He configurado el Zend, para que me imprima el “Hola Mundo” con la url http://localhost/planeacion, pero necesito utilizar esta misma configuración, (de Alias en especial) para que cuando digite http://localhost/planeacion/aplicacion1…2…3…
    Pueda ver la aplicacion1…2…3…, que son desarrollos que ya he logrado, pero que no me permiten configurar mas Alias en el config de apache (por “politicas”) gracias a tu idea de colocar un directorio independiente para cada aplicación en el public/aplicacion1…2…3…, he logrado presentar el siguiente error:
    Fatal error: Uncaught exception ‘Zend_Controller_Dispatcher_Exception’ with message ‘Invalid controller specified (planeacion)’ in C:\Desarrollo\planeacion\library\Zend\Controller\Dispatcher\Standard.php:241 Stack trace: #0 C:\Desarrollo\planeacion\library\Zend\Controller\Front.php(934): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http)) #1 C:\Desarrollo\planeacion\prestadores\library\Base\Application.php(209): Zend_Controller_Front->dispatch() #2 C:\Desarrollo\planeacion\public\prestadores\Index.php(13): Base_Application->run() #3 {main} thrown in C:\Desarrollo\planeacion\library\Zend\Controller\Dispatcher\Standard.php on line 241.

    La verdad, sé que algo de concepto tengo bastante mal, me gustaría que me guiaras en este inconveniente.

    Entre otras si digito http://localhost/planeacion perfectamente imprime el “Hola Mundo”.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>