Zend Framework 1 tutorial Part 5: The index.php file

Zend Framework 1 Logo

Go into the public folder and create a new file called index.php. As I already mentioned in the htaccess chapter, this file receives all the requests and passes them to the Zend Framework which will dispatch them.

Zend Framework's controller uses the frontcontroller design pattern. All requests to the frontcontroller will get rooted through a single entry point, the index.php file.

The index.php will create an instance of zend application and run the application bootstrap process by using the bootstrap.php that we will create in our application folder.

Set the application and upload path

First we define an APPLICATION_PATH, we will use it on several files in our application. Then we define the UPLOAD_PATH which will be used in our application everywhere we need the path of the uploads folder.


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

// Define path to the upload directory
define('UPLOAD_PATH', realpath(dirname(__FILE__).'/upload'));

Check for APC support

The next two lines will be used in our bootstrap to check if the APC extension is available.


// check for apc support
define('APC_SUPPORT', extension_loaded('apc') && ini_get('apc.enabled'));

Set the application environment

Now we define an APPLICATION_ENVIRONMENT. We try to use the value we have set in our htaccess file. If for any reason it's still not set we define production as our default environment type.


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

Add the library to PHP's include path

Next we add the path to the library directory to the php include path.


// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/../library'),
    get_include_path(),
)));

The autoloader

Then we require Zend Framework's Autoloader file. Forget the include, include_once and other require, you won't need them anymore. Every time you will try to use a class that has not yet been loaded, the Zend Framework will load it for you. The ZF autoloader is a namespace autoloader, which uses an optimistic matching of namespaces to filenames to retrieve the correct file. Let's you use instantiate a class called Zend_Db_Table, then the ZF will now that it has to autoload the file library/Zend/Db/Table.php.


// create a autoloader instance
require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();

// put autoloader instance in registry to retrieve it in bootstrap
Zend_Registry::set('Autoloader', $autoloader);

For more information about the Zend Framework autoloader check out the Zend Framework autoloader documentation.

The configuration file

1) We set some variables like the path to cache folder or the configuration file.


// define some values needed by the cache
$cacheDirectory = APPLICATION_PATH.'/caches/';
$configurationPath = APPLICATION_PATH.'/configs/application.ini';
$configurationName = 'applicationconfiguration';
$cacheLifetime = 2678400;

2) We check if the cache directory exists, if not we create it.


// check if the cache directory exists, if not create it
if (!is_dir($cacheDirectory)) mkdir($cacheDirectory, 0755);

3) We setup the cache backend and frontend options for our cache instance. We will use the frontend adapter file as well as the backend adapter file, because with that type of cache we can change values in our configuration file (the application.ini file) and next time we run our application the cache will notice that our configuration file changed and will reload it.


// if no lifetime is defined default will be 3600
$frontendOptions = array(
	'master_files' => array($configurationPath),
	'automatic_serialization' => true,
	'lifetime' => $cacheLifetime
);

$backendOptions = array('cache_dir' => $cacheDirectory);
$configurationCache = Zend_Cache::factory('File', 'File', $frontendOptions, $backendOptions);

Instead of using the master files cache you could also use the APC cache backend if APC is available on your system, this code for example could be used to check if APC is available or fallback to the files cache:


if (APC_SUPPORT) {
    
    // if no lifetime is defined default will be 3600
    $frontendOptions = array(
        'automatic_serialization' => true,
        'lifetime' => $cacheLifetime
    );
    
    $backendOptions = array();
    
    $configurationCache = Zend_Cache::factory('Core', 'Apc', $frontendOptions, $backendOptions);
    
} else {
    
    // if no lifetime is defined default will be 3600
    $frontendOptions = array(
        'master_files' => array($configurationPath),
        'automatic_serialization' => true,
        'lifetime' => $cacheLifetime
    );
    
    $backendOptions = array('cache_dir' => $cacheDirectory);
    
    $configurationCache = Zend_Cache::factory('File', 'File', $frontendOptions, $backendOptions);
    
}

APC is a PECL extension. It's a memory store, which means that it caches the data in the RAM instead of the disc, which brings a speed improvement and reduces disc io (writes / reads). The disadvantage compared to the masterfiles cache, is that if you change the configuration file content, you will have to clear the APC cache as it won't notice by itself that the configuration file has changed and that therefore the cache needs to be refreshed. To clear the cache you could add a few lines to your deployment script that clears the cache on your production machines every time you do an export.

4) Then we check if the configuration is in the cache, if it is we will use the cached configuration. If its not cached (because the cached version expired or its first time we run the application) we will load the configuration and put it into the cache. We pass the environment ass parameter to zend config ini, to load the configuration values corresponding to the environment that is set right now. We will have different configurations for development, testing and production mode.


if (!$configuration = $configurationCache->load($configurationName)) {
	$configuration = new Zend_Config_Ini($configurationPath, APPLICATION_ENVIRONMENT);
	$configurationCache->save($configuration, $configurationName);
}

4) Now we put the configuration in the registry to be able to reuse it anywhere else in our application without having to load it again.


// store configuration in registry
Zend_Registry::set('Configuration', $configuration);

5) Now we are ready run the application. We create an instance of zend application by passing the environment type and our configuration values to the application constructor.


// create an application instance
$application = new Zend_Application(
    APPLICATION_ENVIRONMENT,
    $configuration
);

6) We will use try catch, to catch exceptions if bootstrapping fails. If an exception gets catched we check what environment type is active, in production mode we only output the error message. If we are not in production mode it means we are in development or testing mode and we also output the stactrace of the error to help us understand the error and therefore debug the application.


// BOOTSTRAP
try {
   $application->bootstrap()->run();
} catch (Exception $exception) {
    echo '<html><body><center>'
       . 'An exception occurred while bootstrapping the application.';
       print_r($exception->getMessage());
    if (defined('APPLICATION_ENVIRONMENT')
        && APPLICATION_ENVIRONMENT != 'production'
    ) {
        echo '<br /><br />' . $exception->getMessage() . '<br />'
           . '<div align="left">Stack Trace:'
           . '<pre>' . $exception->getTraceAsString() . '</pre></div>';
    }
    echo '</center></body></html>';
    exit(1);
}

Note we will not use the php closing tag at the end of our php files, Zend recommends that for PHP scripts the closing ?> can be omitted.

Here is the full index.php file:


<?php

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

// Define path to the upload directory
define('UPLOAD_PATH', realpath(dirname(__FILE__).'/upload'));

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

// check for apc support
define('APC_SUPPORT', extension_loaded('apc') && ini_get('apc.enabled'));

// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/../library'),
    get_include_path(),
)));

// create a autoloader instance
require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();

// put autoloader instance in registry to retrieve it in bootstrap
Zend_Registry::set('Autoloader', $autoloader);

// define some values needed by the cache
$cacheDirectory = APPLICATION_PATH.'/caches/';
$configurationPath = APPLICATION_PATH.'/configs/application.ini';
$configurationName = 'applicationconfiguration';
$cacheLifetime = 2678400;

// check if the cache directory exists, if not create it
if (!is_dir($cacheDirectory)) mkdir($cacheDirectory, 0755);

if (APC_SUPPORT) {
    
    // if no lifetime is defined default will be 3600
    $frontendOptions = array(
        'automatic_serialization' => true,
        'lifetime' => $cacheLifetime
    );
    
    $backendOptions = array();
    
    $configurationCache = Zend_Cache::factory('Core', 'Apc', $frontendOptions, $backendOptions);
    
} else {
    
    // if no lifetime is defined default will be 3600
    $frontendOptions = array(
        'master_files' => array($configurationPath),
        'automatic_serialization' => true,
        'lifetime' => $cacheLifetime
    );
    
    $backendOptions = array('cache_dir' => $cacheDirectory);
    
    $configurationCache = Zend_Cache::factory('File', 'File', $frontendOptions, $backendOptions);
    
}

if (!$configuration = $configurationCache->load($configurationName)) {
	$configuration = new Zend_Config_Ini($configurationPath, APPLICATION_ENVIRONMENT);
	$configurationCache->save($configuration, $configurationName);
}

// store configuration in registry
Zend_Registry::set('Configuration', $configuration);

// create an application instance
$application = new Zend_Application(
    APPLICATION_ENVIRONMENT,
    $configuration
);

// BOOTSTRAP
try {
   $application->bootstrap()->run();
} catch (Exception $exception) {
    echo '<html><body><center>'
       . 'An exception occurred while bootstrapping the application.';
       print_r($exception->getMessage());
    if (defined('APPLICATION_ENVIRONMENT')
        && APPLICATION_ENVIRONMENT != 'production'
    ) {
        echo '<br /><br />' . $exception->getMessage() . '<br />'
           . '<div align="left">Stack Trace:'
           . '<pre>' . $exception->getTraceAsString() . '</pre></div>';
    }
    echo '</center></body></html>';
    exit(1);
}