Overview
There'll be times when, as an aspiring PHP developer faced with a new project, you'll think that the mountain ahead of you seems almost impossible to climb.
Finding the right psychological starting point can be tricky for the best of us, but one of the most satisfying things to discover at the start of the project is that half of what you figured you'd have to write has already been written.
As your portfolio of PHP projects matures, you'll find that you can reuse much of your own code from previous projects (yet another reason why taking a modular, object-oriented approach to your work is highly recommended). So-called "search-and-replace" development has saved thousand of engineer hours over the years.
There will be times, of course, when you simply have nothing to fall back on. Some components can be immensely time-consuming to develop without actually contributing to the core ethos of your project. That is when the "blank canvas" syndrome can kick in, and the urge to make just one more cup of coffee before you get started takes hold.
Thankfully, there is an answer: a repository of thousands of useful, fully tested, re-usable PHP components, all of which are broadly free to use and include in your own application.
In this post, you explore this repository; and discover why it exists, and how it can help you. You find out when—and when not—to use it. Most importantly, you learn how to identify the components most relevant to your project, and how to integrate them into your application.
What is PEAR?
PEAR—the PHP Extension and Application Repository—was set up in 1999 by one of the PHP project's most respected and longest-serving contributors, Norwegian Stig Sæther Bakken. Its principal purpose is to provide an officially sanctioned library of open-source components contributed by PHP architects from all over the world, as well as an integrated means for installing those components into installations of PHP.
Those with experience of PERL may well draw similarities to the Comprehensive Perl Archive Network (CPAN), and would be right to do so. PEAR borrows many of the excellent features offered by CPAN, including the detection and automatic installation of dependent components when installing modules.
The components—or packages—within the PEAR network cover a myriad of functionality, including database connectivity, support for reading and writing unusual file formats, and widgets for generating complex HTML. Many components feature XML support.
In addition, PEAR provides a set of coding standards to which its contributors must adhere, which we examine shortly.
How is PEAR Structured?
The PEAR Project is divided into a number of missions:
• A library of packages, each representing a discrete area of functionality.
• The PEAR Package Manager, used for installing and removing these packages from an installation of PHP.
• The PHP Foundation Classes (PFC), a subset of the PEAR repository consisting of modules of a highly stable and thoroughly tested nature, which are included in a standard PHP installation.
• The PHP Extension Community Library—PECL—a library of components written in C (rather than native PHP), which has just recently become a project in its own right (see http://pear.php.net for more information).
Any single package found in the PEAR repository is almost always distributed as a class. Because the packages are designed as reusable, modular components, an object-oriented methodology makes a great deal of sense.
The PHP Foundation Classes
The PHP Foundation Classes (PFC), which are included by default in a normal installation of PHP, offer a number of essential toolkit routines beyond the basic intrinsic functionality of PHP. Although still, strictly speaking, unofficial, their common use in PHP applications is considered standard and accepted.
Packages within PFC generally have large scopes of use, rather than concerning themselves with, for example, obscure database platforms or file formats. Furthermore, such packages are always considered stable. At the time of this writing, some of the foundation classes distributed with PHP5 include the Mail class, an OS Guess class for determining the host operating system in PHP, and classes for making socket connections to other network hosts. Some of these classes may seem a little obscure in their own right, but nonbundled PEAR classes often make substantial use of them. By distributing them with PHP, the Package Manager does not have to install them on your behalf when you install a PEAR class that requires them. The PFC classes are always optimized for the version of PHP with which they are bundled; were it left to the Package Manager to download a copy, obscure incompatibilities between versions of PHP and versions of the PFC classes might start to cause problems. Explicitly tying PFC classes to distributions provides a common interface to the core of PHP such that non-PFC PEAR classes do not have to concern themselves with any differences between PHP versions.
If you are curious to know which modules are included as part of the Foundation Classes, check out the /usr/local/lib/php (Unix) or C:\PHP\PEAR (Windows) folder on your fresh PHP installation. Documentation for usage of these classes resides, like any other PEAR class, on the PEAR Web site at http://pear.php.net.
As these packages are included in a standard installation of PHP, you should not need to install them by hand, unless you explicitly requested they not be installed when you set up your development environment.
In theory, you can keep them up-to-date by using the PEAR Package Manager (more on this shortly), but in practice they are upgraded as and when new versions of PHP become available.
The PHP Extension Community Library
The PHP Extension Community Library or PECL (pronounced pickle) was originally a subset of the PEAR repository consisting of components written in C, rather than in native PHP. The rationale behind such components is usually the need for speed; compiled C often works out a lot quicker than PHP, particularly for mathematically intensive operations. PECL offers a means for component developers to avail themselves of the speed and power of C, whilst continuing to provide an interface to those components through standard PHP syntax.
PECL has recently evolved into a project in its own right, completely separate from PEAR—although it does retain the layout and politics of PEAR.
PECL is outside the scope of this post; however, familiarity with PEAR should leave you in good stead to tackle PECL should you want to do so. A good starting point is the project's Web site: http://pecl.pear.net.
The PEAR Package Manager
Many of the packages in the PEAR repository have dependencies. A dependency is the existence of a requirement for one class to be installed in order for another to function successfully. For example, a PEAR component that provides the capability to perform HTTP POST requests may depend on the existence of a generic HTTP functionality package. That package may in turn depend on a TCP/IP abstraction package, and so on.
As you can tell, starting with a fresh PHP installation and installing all necessary dependencies to make your class of choice function correctly could be immensely difficult to do by hand. The process is made much easier by means of the PEAR Package Manager.
The Package Manager provides a wealth of functionality for managing the insurgence of PEAR into your PHP setup, but its principal purpose is to allow you to install and remove PEAR packages with ease.
It is dependency-aware, which means that when you ask it to install a particular package that depends on one or more other packages, it kindly installs those dependent packages for you. It's also aware of the hierarchy of dependency, so it ensures that those packages are installed in the correct order.
Installing packages using the PEAR Package Manager is covered later in this post.
Control Structures, Comments, and Indenting
PEAR dictates that all code should be indented appropriately according to its context by using a suitable number of spaces (not tabs). In the case of PEAR, it's four spaces.
You may be able to configure your editor of choice such that when the tab key is pressed, four spaces are rendered instead of an actual tab character.
As well as being indented, PEAR requires that constructs err on the side of verbosity. For example, if a parenthesis is optional but its inclusion improves clarity, then its inclusion is required. White space should be used only to separate out distinct lines and thoughts, and where it is included for reason of clarity, it should be kept as minimal as possible.
Curly braces should always be used in control structures (while/if/switch/for/foreach) even when there is only a single line within the block, and that's why the use of braces is not required by the PHP interpreter. This improves clarity immeasurably. The opening brace should always begin on the same line as the start of the control block. The closing brace should fall on a new line. PEAR does not comment on whether it is appropriate to suffix the closing brace with a semicolon.
Starting and finishing blocks of PHP by means of the <?php and ?> operators should always include the optional letters php for reasons of clarity.
Comments are encouraged wherever it would improve readability to include them. Avoid using the # comment predicate, even though PHP allows it; instead, opt for C-style // (for a single-line comment) or /* and */ (to begin and end a multiline comment).
Here is an example of a PEAR-compliant control structure:
<?php
if ((($x == 14) && ($y == 19)) || $z = 24) {
print($strMyVal. "\n");
// This is a meaningful comment
};
?>
Function Calls and Definitions
When calling a function, there should be no space placed between the name of the function and its opening parenthesis prior to its argument list. If there are no arguments to be passed, a blank list should be used by opening and then immediately closing parentheses, as this example shows:
<?php
$strMyVar = myFunction($strA, $strB, $strC);
$strAnotherVar = anotherFunctionWithNoParameters();
?>
When declaring your own functions, the rules for braces in control structures are changed slightly; the starting brace for the block should begin on a new line, immediately after the function name and argument list definition. Here's an example of that syntax:
<?php
function myFunction($strArg1, $strArg2)
{
return($strMyResult);
};
?>
In the argument list, arguments that are optional should be designated by using the $strArg = " methodology. Optional arguments should always be last in the argument lists.
Finally, functions should always return a value if it is meaningful to do so. At the very least, a function should return whether or not it was successful in its designed endeavors.
Naming Conventions
Naming of variables, classes, and functions in languages that have weak typing (are loosely typed), such as PHP, is of immense importance.
PEAR conventions require the following:
• Classes should begin with a capital letter, such as Publisher. If the class has hierarchical placement within PEAR, this should be reflected in the name, such as HTML_TreeMenu, where TreeMenu is a component within the HTML hierarchy of PEAR.
• Functions should be named using the name of their parent package followed by an underscore (if applicable), and then a descriptive name without underscores; the descriptive name should have its first word or syllable lowercase, with the first letter of each subsequent word or syllable (as appropriate) capitalized (XML_RPC_serializeData) Private member functions or variables of classes accessed only from inside other methods of that class should be prefixed with an underscore ($this->_currentStatus).
• Constants should be capitalized, with underscores used to separate words, such as $HOME_DIRECTORY.
PEAR does not voice an opinion about naming convention for working variables. Many PEAR authors have adopted Hungarian Notation whereby the expected contents of a variable are alluded to in its name; for example, $strMyVariable is designed to hold a string, and $intMyNumber is for holding a number.
The authors strongly suggest you adopt this method, except where it is awkward to do so; for example, counter variables for for loops might reasonably make use of $x, $y, and $z, but these should never be used for variables holding meaningful integers.
Installing PEAR Packages
Installing PEAR packages is remarkably easy. Far trickier is tracking down the right package for your project. Often, there is a steep learning curve in simply familiarizing yourself with a package's interface to the point that you can play with it to assess its feasibility. As PEAR matures, however, so will its packages, and the documentation supplied with them will improve immeasurably.
Finding Your Way Around pear.php.net
A good starting point for finding PEAR packages is to visit the PEAR home page, http://pear.php.net.
If you know what package you want to install, you can jump right to "Using the PEAR Package Manager," but if you're just after a certain bit of functionality, you can use the PEAR site to browse through available packages, or even search based on a keyword.
To browse packages, click the Packages link at the top-right of the screen. If you've ever used Yahoo! or any other hierarchical directory engine, this should look pretty familiar. Select the category in which you're interested, and you get a list of all the packages stored under that category.
Unlike Yahoo!, however, PEAR never goes more than one level deep; click HTML, for example, and you see every single package under the HTML organizational structure, there's no such thing as a subcategory. Pagination buttons keep screen flood to a minimum.
Sadly, the search page on PEAR is rather lacking—it currently only searches the package names, not their descriptions. Whether you can find anything in this manner is anyone's guess. If you want to play, however, there's an integrated search form at the top of every page on PEAR. Type a few words there and click the button.
Exploring PEAR Classes and Applications
Once you've found a package to look at, click its name and you are taken to its home page. From there, you can view the package's revision history, see what dependencies (either parent or child) it has, and browse some fascinating package statistics.
Importantly, many packages here have a link to View Documentation, which takes you to a well-laid reference detailing the package's various classes, methods and routines. If you have ever used the PHP Web site reference at www.php.net, this will probably seem comfortingly familiar.
The one thing you probably shouldn't try to do from this page is download a release of the package. Unless you're absolutely stuck, you're far better off using the PEAR Package Manager. Manual installation is possible, of course, but is outside the scope of this post—the PEAR Web site details the process for this.
Knowing when to turn your back on PEAR is every bit as important as knowing when to greet it with open arms. Although the repository is home to some great software, a handful of the packages are unfinished or unstable in some way—and some may simply not be your cup of tea. Planning your PHP project involves identifying where repositories like PEAR can help and where they can't well in advance, so don't be afraid to play with components in a sandbox environment before you commit to any deadlines. If you do find yourself forced to author a component from scratch, why not offer it to PEAR for incorporation into the repository? Not only will thousands of others get to benefit from your programming prowess, but you yourself will benefit from a warm, fuzzy feeling for weeks to come.
Installing and using the PEAR Package Manager
The PEAR Package Manager is bundled with all modern versions of PHP, and certainly all v5 releases.
For Linux and UNIX installations, the Package Manager should already be installed, unless you explicitly requested it not be installed when you first set up PHP.
For Windows installations, however, there is an extra step you need to follow. Linux users can skip this section.
Keep in mind that if you're deploying your finished application to a live server, such as a Web server hosted by an Internet services provider (ISP), the ISP must install any PEAR packages required by your application before it will work correctly. If your ISP won't do this for you, you can install the PEAR packages by hand, although you won't benefit from the automatic detection of missing dependencies. There's more information about installing PEAR packages by hand on the PEAR Web site.
Setting up the PEAR Package Manager on Windows
In this example installation, it's assumed that you have installed PHP in C:\PHP (the default). If this is not the case, simply change the syntax to fit your own installation directory.
Open a command prompt and run the following:
C:\>cd php\pear
C:\php\PEAR>..\php go-pear.php
Welcome to go-pear!
The script on screen guides you through the process of setting up the Package Manager. Its ultimate aim is to simply create an executable called pear that you can run, just like those on Linux/UNIX distributions.
The script asks you for an HTTP proxy server because it needs to download and update the PEAR Foundation Classes from the Internet. This setting is recorded and used in any subsequent downloads of PEAR packages, so it's important to be precise here. Most users won't need to specify anything here; if you're unsure, ask your ISP or your Systems Administrator, as appropriate.
The default installation directories are fine for most users, so just hit the Enter key when prompted.
When asked if you want to install the PEAR packages bundled with PHP, say yes.
The packages will download, unpack, and barring any problems with your Internet connection, install into your normal PHP library path. The pear executable is created in C:\PHP; run it to start the PEAR Package Manager. If you specified a proxy server, this setting is retained.
You're now ready to use the Package Manager!
Using the PEAR Package Manager
To run the Package Manager, open up a command prompt (Windows) or command shell (UNIX).
Ideally, you need to be an administrator or root (as appropriate) to use the Package Manager, otherwise you may find that you don't have permission to write to the PHP library folder.
There're a myriad of different commands, but the most useful ones are likely to be install, uninstall, and upgrade. Here's the syntax for them:
pear install component_name
pear uninstall component_name
pear upgrade component_name
Make sure you enter the component name carefully, keeping any capitalization, spacing, and underscores intact. With a bit of luck, you should see output that looks something like the following:
root@genesis:~# pear install HTML_TreeMenu
downloading HTML_TreeMenu-1.1.9.tgz ...
...done: 49,213 bytes
install ok: HTML_TreeMenu 1.1.9
root@genesis:~#
This indicates everything went okay—the PEAR Package Manager managed to connect to PEAR, download the package (and any dependent packages), and install the lot.
If you see a large number of warnings about things being "deprecated," don't panic. Some packages on PEAR are written for PHP4, and version 5 sometimes complains if the syntax of the package you are installing isn't particularly version 5-friendly. Most of the time, these warnings can be safely ignored; if the package installs successfully, all is well. It's worth checking the PEAR Web site, which you'll meet later, to see if there are any useful compatibility notes about the package you're installing.
Generally speaking, PEAR has to put the module in your PHP library directory, which is usually something that's defined on a per-server instead of a per-user basis, hence the need to have administrative privileges.
There may be (such as with the HTML_TreeMenu component described later) additional steps before you can usefully incorporate the package in your code. Refer to the package documentation to determine what these might be. You may, for example, be required to copy data files (such as GIFs and JPEGs, XML configuration files etc) to a more meaningful location for your project.
Using PEAR Packages
By now you should have a good grasp of how to identify a good PEAR package to use in your project, how to install it and any of its dependencies, and how to incorporate it into your own code. Let's put that knowledge to work to build a working application using a single PEAR component and a few more common built-in PHP routines.
Building an Application using Two PEAR Components
Let's put all your PEAR skills together now, and build a fresh application from the ground up. Let's see if you can combine the use of the two PEAR components you've met so far—HTML_TreeMenu and MP3_ID—to build a genuinely useful application.
The Application
Some of the more enlightened Internet radio stations these days, as well as traditional broadcast radio stations with an online presence, offer some facility for its listeners to request music via the station's Web site.
With a limited play list, it would be unwise for a station to allow a free-text request form because many of its listeners' requests would have to go unfulfilled. Generally speaking, such stations would normally want to offer a list of all tracks in the station archive, and let the listener to choose from that list.
Constant new additions to that archive, which is normally made up of MP3 files, could make maintaining the request part of the Web site pretty tricky. As a result, some means for the request list to be generated dynamically and be arranged in some sensible manner would be just swell.
This application permits just that. It presents all the MP3 files in a server's directory in a hierarchical list (using the HTML_TreeMenu PEAR component), ordered by artist. It enables the submitting user to click a particular song to request it, and then render an e-mail to the DJ of the radio station instructing him to play that file.
You'll use PHP's built-in mail() function to send this e-mail. This is a very simple way to send e-mail, and in most real-world applications, you'll need something a little chunkier.
Because you've used XML to drive the contents of the output of the HTML_TreeMenu component so far, let's stick with that method. You'll still need to use the helper class, however, to turn the XML into PHP methods that HTML_TreeMenu can understand.
Architecture
The application can be divided into two distinct PHP files, just to make things a bit neater. The first, radiogeneratexml.php, generates an XML representation of the MP3 folder on the server, organized and ordered by artist. The second, radiorequest.php, actually displays that list, and handles any form submissions by the user.
The XML gets from one script to the other by means of an HTTP request. Yes, your script will cause your server to make a request from itself! If you've ever played with the idea of XML-based Web services, this might not seem so crazy. The idea is to allow the feed of XML data to come from practically any source, in practically any location. For example, in a real live radio station you might use one Web server to serve the public Web site, but a totally separate server to hold the MP3 files. The server holding the MP3s might not even be accessible to the outside world. Instead of trying to read over any kind of network share, which is incredibly inefficient, you could place radiogeneratexml.php on the server with the MP3s, and keep radiorequest.php on the public Web server, and tell it to request the XML straight off the other server.
Should you ever decide to extend your application so that third-party Web sites could access the data, you just might make that XML feed public.
The XML, for the purposes of this application, conforms to the standards required by the HTML_TreeMenu component,
which you have already seen. With the possibility of some kind of secondary use of the XML feed in mind, it may be wise to consider, as a project for a rainy day, upgrading the application to produce XML in a more service-driven than display-driven format. You could then use a simple XSL style sheet to convert the service-driven XML into XML that the PEAR component could understand.
Generating the XML
radiogeneratexml.php not only is in charge of producing XML that can be used by the make-a-request page, but also is in charge of reading the MP3 directory, extracting the useful artist and title data from each MP3 file, and then grouping and sorting the list of MP3s in an appropriate way.
Let's just quickly review the kind of XML you want to produce for the HTML_TreeMenu component. Take a look at this example output:
<?xml version="1.0"?>
<treemenu>
<node text="Extreme Metal Grinding" icon="folder.gif">
<node text="Extreme Noises" icon="document.gif"
link="radiorequest.php?requestfile=9991885931034.mp3" />
<node text="Extreme Temper Loss" icon="document.gif"
link="radiorequest.php?requestfile=9991885931035.mp3" />
</node>
<node text="Massive Pitch Correction" icon="folder.gif">
<node text="How long ago" icon="document.gif" link="radiorequest.php?requestfile=9991885931036.mp3" />
<node text="Ten minutes to Sunrise" icon="document.gif"
link="radiorequest.php?requestfile=9991885931037.mp3" />
</node>
</treemenu>
In this output, you can see that two artists have been identified in the MP3 collection: "Extreme Metal Grinding" and "Massive Pitch Correction" (this isn't the greatest radio station in the world). The available songs by each of these two fine artists have been placed under their nodes in the hierarchy.
The name of each song is the caption for the link itself—to radiorequest.php—passing a GET parameter called requestFile. The actual MP3 filename is passed because it is of more use to the DJ than the information from the IDv3 tag of the file. PHP's urlencode() function will make sure the MP3 filename is URL-friendly before it's passed, of course.
If you want to see what this will look like when rendered by HTML_TreeMenu, use your code from the first "Try It Out" example in this post and paste this XML into treemenutest.xml. You then need to modify treemenutest.php to look at the correct XML file:
$objXMLTree = new XMLHTMLTree("treemenutest.xml");
In this post, you were introduced to PEAR, the PHP Extension and Application Repository.
You discovered how to browse the PEAR Web site to identify suitable packages for use in your applications, and how to download and add those packages into an installation of PHP. You also picked up a decent grasp of how the PEAR project is structured, which should make it easier for you to find what you're looking for in the future.
You also found out how to explore the interface of a new PEAR component and assess its feasibility for incorporation in your project—and you've been forewarned about some of the idiosyncrasies of PEAR packages and how to overcome them.
You refreshed your knowledge of the PEAR coding standards adhered to throughout this post, as well as examining the rationale behind them.
Finally, you met the challenge of producing a functional, useful application using a number of PEAR packages.