One of the most common mistakes made by the new PHP developer is the failure to properly define the structure of an application’s code base.
Organizing your application code before you start the project will save time, yield more maintainable code, and if done correctly result in a more secure application structure.
When coding PHP for a large scale project it makes sense to follow the Zend PHP coding standards. You will notice that the majority of the code I release makes an attempt to follow these for readability.
Excessive include statements are often the source of performance losses in PHP. As a result the
include_once statement was introduced to check if a file has previously been included. While this
would be fine as a compiler directive it is actually costly in terms of CPU time (especially if you have hundreds of them).
As a developer you should know exactly what has been included or not at any point in the source code. If you
don't take the time to design your application structure this may quickly become difficult.
Another common mistake that PHP developers make is to place Library PHP files in a web-accessible directory. This can result in unexpected access to files that should never be accessed directly by the user. That is a problem in itself, but even more disconcerting, the fact that if a web server is miss-configured and no processing PHP files, the source can be returned to the user instead of the processed data exposing potentially sensitive information such as passwords.
Thirdly, for include statements to be efficient; they should always use explicit full or relative paths. You should never have to search the include path or run a function to determine where your file lives. While it may seem trivial for smaller projects, once used in a larger project you can actually see a measurable compute-time difference (often close to or over a second).
Placing these files outside the web root solves these problems.
I commonly use the following directory structure as a starting point for new web applications:
project/
htdocs/
htdocs-ssl/
ssl/
cert.pem
key.pem
log/
access.log
error.log
ssl-access.log
ssl-error.log
lib/
init.php
_config.php
This directory structure is similar to what you would create for an Apache virtual host. You could also create an Alias for the directory to include it as a sub-directory of an existing website (useful if you do not run virtual hosting). In this case you would leave out the log and ssl directories.
Assuming we place our project directory in the /srv root (yes, that's what it's there for) here is an
example Apache configuration for a virtual host.
<VirtualHost 192.0.2.1:80>
ServerName project.example.com
DocumentRoot /srv/project/htdocs/
ServerAdmin webmaster@example.com
ErrorLog /srv/project/log/error.log
CustomLog /srv/project/log/access.log combined
</VirtualHost>
<VirtualHost 192.0.2.1:443>
ServerName project.example.com
DocumentRoot /srv/project/htdocs-ssl/
ServerAdmin webmaster@example.com
ErrorLog /srv/project/ssl-error.log
CustomLog /srv/project/ssl-access.log
SSLEngine on
SSLCertificateFile /srv/project/ssl/cert.pem
SSLCertificateKeyFile /srv/project/ssl/key.pem
</VirtualHost>
And here would be an example using a directory Alias.
Alias /project "/srv/project/htdocs"
<Directory "/srv/project/htdocs">
Options Indexes MultiViews FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
</Directory>
For more information on configuring Apache, see the Apache HTTP Server Documentation.
Going back to our directory structure, you'll notice that there were two files in the lib directory,
init.php and _config.php.
lib/
init.php
_config.php
The lib directory is where we will store all PHP include files. The init.php file will make all
the PHP includes (functions, classes, global variables) required by every page, including the _config.php
file which will store configuration variables for the project (such as Database connection information). This
creates a situation where for most PHP files in the web root, only one include statement is needed (and
init.php includes the rest). The exception to this are situations where an include may only be
required for a small set of files. While we could include everything we need using init.php, it's
better to keep it as light as possible.
You will also notice that the _config.php file is prefixed with an underscore _. This
is a naming convention used to show that the file is included elsewhere; in this case, init.php. As a
general rule, we will never include a file that begins with and underscore directly outside of our library.
Let's assume that along with our configuration we have a database wrapper class to include. Here would be a
sample init.php.
<?php
require '_config.php';
require '_EasyMySql.php';
$db = new EasyMySql($db_hostname, $db_username, $db_password, $db_database);
Notice that we use the require statement rather than the include statement. Require
is identical to include except that it will halt execution on failure (which is what we want). Also notice that we
omit the PHP close tag. This prevents accidental whitespace from being included. Here would be a sample
_config.php.
<?php
$db_hostname = '127.0.0.1';
$db_username = 'project';
$db_password = 'password';
$db_database = 'project';
Now, in the web root, we would create our index.php file using the init.php include.
<?php
require '../lib/init.php';
?>
The index.php file now has direct access to the database object. Note that the database object was
initialized in the init.php; this was to demonstrate that init.php can also be used to
initialize some global variables, however, if not every page requires database access it may be a better idea to only
create the object as needed.
By following these simple guidelines, you can save a lot of development time, and create a project directory that has all your most commonly used code which can then be used as a base when you create new projects.
This site is published by Ray Soucy, 239 Forest Avenue, Orono, ME, 04473.
Copyright © 2009, by Ray Patrick Soucy.This page was accessed on 2010-09-06 00:45:24 EDT by 38.107.191.94