When using Zend Framework, its library must be present in the PHP directive ‘include_path‘, so a common thing to do when using ZF is to set the include_path inside the app and include a directory where the ZF library is supposed to be installed.
Here’s my problem: Instead of hard-coding a path to a directory that may or may not contain the framework, I wanted a simple way to configure include_path without having to override the global setting through php.ini, .htaccess, etc. Naturally I can’t use Zend_Config which I’d otherwise use for configurations.
The directory structure I’m using is based on the structure suggested in the tutorial Getting Started with the Zend Framework by Rob Allen. This means that I have 3 directories in the application root directory, ‘app’ for application files, ‘lib’ for libraries (such as Zend Framework) and ‘pub’ for public files (css, js, images, etc). I could just ship my application with a copy of Zend Framework inside the lib-directory and leave it at that, but I don’t want that since people may already have a copy of the framework on their servers and may not want another copy for storage reasons or just simplicity.
The solution I came up with was to create simple text-files in my applications lib-directory containing paths to include in include_path. My app would then scan this directory and extract the contents of all files matching a given extension before setting include_path using these extracted values. The extension I went with for these simple config-files was ‘.libp’, short for ‘lib-path’.
In my application object constructor, I now have
define('DS', DIRECTORY_SEPARATOR); define('PS', PATH_SEPARATOR); define('AR', realpath(dirname(__FILE__) . '/..')); # application root try { self::_set_include_path(); if(!@include_once('Zend/Loader.php')) { throw new Exception('Failed to load Zend Framework. This is a required library and must be installed.'); } } catch(Exception $e) { echo $e->getMessage(); exit; }
I think the code is fairly obvious, so I won’t waste time commenting it further.
Later in the same class, I have these methods
private static function _set_include_path () { $customLibPaths = ''; $libPath = self::getPath('lib'); # filter out non-regular files, files starting with a punctuation mark and files not ending with .libp foreach (array_filter(scandir($libPath), create_function('$file', 'return (strpos($file, \'.\') === 0 || !is_file(\'' . addslashes($libPath . DS) . '\' . $file) || pathinfo($file, PATHINFO_EXTENSION) !== \'libp\' ? false : true);')) as $file) { $tmpPath = trim(file_get_contents($libPath . DS . $file)); if (empty($tmpPath)) { continue; } if (!is_dir($tmpPath)) { throw new Exception(sprintf('"%s" is not an existing directory, please change %s to contain a real include path. If you don\'t want to set a new include path in this file, you may either delete it or empty it.', $tmpPath, $libPath . DS . $file)); continue; } $customLibPaths .= PS . $tmpPath; } set_include_path( AR . PS . AR . DS . 'lib' . $customLibPaths . PS . get_include_path() ); } /** * Get absolute path to a directory or file by passing any number of path entities (directories/files) relative from the application root */ public static function getPath () { $args = func_get_args(); # Can't be used as a function parameter directly, must be assigned to a variable return AR . DS . implode(DS, $args); }
The lib-directory contains files such as zend-framework.libp, holding a simple string each with the path to the respective libraries. When trying to include files, PHP will now first check the application root, then the lib directory, any custom lib-paths and finally the default include_path.
If I ever want to implement some sort of plugin system for my app, any plugins relying on external libraries may add a file in the lib-directory to configure the include path instead of modifying main application files. I can also use this myself of course if I at a later point want to make use of further third party libraries and allow end-users to easily configure the paths to those libraries.