Developer: PHP
Build an Enterprise-Grade PHP Stack with Zend Server and Oracle Database 11g
by Vikram Vaswani
The quick way to create a Oracle/PHP/Apache/Linux (OPAL) development and deployment environment.
Published May 2009
Over the last few years, PHP has become increasingly popular in the enterprise space, both on account of its friendly licensing terms and its ease of use in building robust, secure applications. It's increasingly being used in conjunction with Oracle Database, the system of choice for large enterprises.
There's only one problem with this happy picture: setting up an Oracle/PHP/Apache/Linux (OPAL) development environment requires some manual steps, which often doesn't fit well in corporate IT environments used to automated simplicity. Online resources such as Oracle's PHP RPMs for Enterprise Linux and reference material such as the Underground PHP and Oracle Manual, Oracle's PHP FAQ Wiki, and various "getting started" guides help for some platforms, but the process still isn't as easy as clicking a bunch of buttons and letting an automated installer do the heavy lifting.
Fortunately, things are changing for the better. And one of the first harbingers of that change is a new release from Zend Technologies: Zend Server, a PHP stack for business-critical applications that runs on both Windows and Linux. It can be used to build Oracle-based applications out of the box. This new product provides a high-performance, enterprise-ready OPAL stack that allows corporate IT departments to add PHP middleware to their existing installations without breaking a sweat. For Oracle users, Zend Server is now recommended over the Zend Core for Oracle product.
Introducing Zend Server
Zend Server is a ready-to-use PHP stack that makes it easy to develop and run PHP application in both Windows and Linux environments. It includes an updated and fully-tested version of PHP, support for a wide variety of database systems, including Oracle, and a number of Zend-specific add-ons for improving PHP performance and diagnostics.
Zend Server is currently available in two versions. If you're reasonably experienced with PHP and are happy to maintain the server and manage updates manually, you can opt for the "community" version of Zend Server, known as Zend Server CE. This version is considered production ready for "non-critical" applications and is available free of charge for Windows, Linux, and additionally Mac OS X; however, it doesn't include the page caching, automatic updates and diagnostic features that are included in the "commercial" version. If these features are important to you—and they should be if you're using the server for business-critical PHP applications—then you should consider purchasing the commercial version of Zend Server, which entitles you to all of the above features plus technical support from Zend. Readers of this article can obtain a 30-day trial license key, provided immediately by clicking the button (registration required) at the link detailed below.
Here's a quick overview of the key features of Zend Server (unless specifically noted otherwise, these features are available in both versions):
- Web-based server management console: Zend Server significantly simplifies the task of managing your PHP development environment, by providing a Web-based interface to PHP configuration and maintenance. Instead of altering PHP parameters by editing a configuration file in a text editor, Zend Server allows you to accomplish the same task via any standard Web browser, using a point-and-click interface. Common tasks such as enabling or disabling extensions, altering the PHP include path or restarting the server can all be accomplished through this Web-based console.
- Performance and diagnostic tools: Zend Server isn't just a pre-packaged version of PHP—it also includes a suite of supplementary tools created by Zend to make troubleshooting and performance optimization easier. This suite includes tools such as the Zend Optimizer+, an extension for run-time performance enhancement; Zend Data Cache, a set of caching functions for use in PHP applications; and Zend Debugger, an extension to help in debugging PHP scripts. The commercial version of Zend Server also includes two additional extensions: the Zend Monitor, which tracks and reports application and server alerts; and the Zend Page Cache, which provides URL-based caching of HTML output.
- PHP certification: Zend Technologies is a well-known vendor of tools for PHP application development and deployment, and every version of Zend Server includes a certified and up-to-date version of PHP that has been tested on different platforms. For large enterprises that are just stepping into the world of open-source technologies, this certification is extremely important to promote a sense of confidence in the PHP platform. Commercial users of Zend Server also have access to a constant stream of security updates, to ensure the integrity of their PHP applications.
Installing Zend Server
For purposes of this article, I'll assume that you already have a version of Oracle installed and working. In case you don't, you can download a version of Oracle suitable for your development system from OTN. The examples in this article were developed using Oracle Database 11g (11.1.0.6.0); however, the PHP extensions bundled with Zend Server also work with other versions of Oracle, including Oracle's free Oracle Database 10g Express Edition.
If you're running Oracle on Linux, chances are you're using either Oracle Enterprise Linux or Red Hat Enterprise Linux. RPM-based installation with yum is the recommended way to install Zend Server on this platform. To accomplish this, the Zend Server manual suggests that you log in as the root user and tell yum about the Zend repository, by creating a new file at /etc/yum.repos.d/zend.repo and adding the following contents to it:
[Zend]
name=Zend PE $releasever - $basearch - Released Updates
baseurl=http://repos.zend.com/rpm/pe/$basearch/
enabled=1
gpgcheck=0
[Zendpe-noarch]
name=Zend PE - noarch
baseurl=http://repos.zend.com/rpm/pe/noarch
enabled=1
gpgcheck=0
Once this file has been created, Zend Server (and its dependencies) can be installed with a single command, as below:
shell> yum install zend-pe
Here's a screenshot of yum at work:
If you're using another, Debian-based Linux distribution, such as Ubuntu, it's useful to know that Zend Server can also be installed using a package manager such as aptitude. The Zend Server manual provides detailed instructions to accomplish this. Briefly, the process requires you to first add the following line to your system's master repository list, at /etc/apt-sources.list:
deb http://repos.zend.com/deb/pe pe non-free
While you're at it, also uncomment the lines for the 'universe' repository so that aptitude can locate and download necessary dependencies; for example:
deb http://archive.ubuntu.com/ubuntu intrepid universe
Then, add Zend's public key to your system's repository database:
shell> wget http://repos.zend.com/deb/zend.key
shell> apt-key add zend.key
Finally, download and install Zend Server, together with all necessary dependencies, using aptitude:
shell> aptitude update
shell> aptitude install
Here's an example of what you might see during the installation process:
Regardless of which method you use, Zend Server will be installed to /usr/local/zend/, and the installer will automatically start it up and present a confirmation message, as below:
Using the Server Administration Console
Once Zend Server has been installed, you can access it using your favorite Web browser at the URL http://localhost:10081/ZendServer. The first time you try accessing it, it will prompt for an administrator password and your license key (get your trial license key for Zend Server immediately—registration required—at this link), as below:
Enter the requested information and you'll be transferred to the server management console, which offers a tabbed interface to the main server administration areas, as below:
Here's a quick list of things you can do through this Web-based console:
Obtain server information: Detailed information on the current PHP build can be obtained from the Monitor → PHP Info page, which displays the uncensored output of the phpinfo() command. Similarly, you will get a birds-eye view of the different installed components of Zend Server via the Monitor → Server Info page, which includes version information and key file paths.
Activate or deactivate server extensions: Zend Server makes it easy to add support for new technologies to your PHP build from the Server Setup → Extensions page, which offers a checkbox-like interface to turn PHP extensions on or off. A similar interface to activate or deactivate Zend's own performance and diagnosis tools, such as Zend Optimizer+ or Zend Monitor, can be found at the Server Setup → Components page.
Modify the PHP configuration file: Normally, altering PHP configuration is a messy affair, requiring you to figure out which PHP configuration variables need to be changed and then manually edit the php.ini configuration file to make the changes. Zend Server significantly simplifies this, by allowing you to edit PHP configuration variables through a single Web form (Server Setup →Directives). This form interface also includes brief snippets of information on each configuration variable, making it easy to quickly figure out what goes where. The Zend Server Web interface also includes a control to restart PHP, making it very simple to immediately see the result of your configuration changes.
Set up page caching: URL-based page caching is one of the most important performance tools available in Zend Server (this feature is not available in Zend Server CE). This feature, accessible from the Rule Management → Caching page, allows the server administrator to set up URL matching rules (based on regular expressions) and have the output of those URLs automatically cached by the server, so that subsequent requests for the same URL are served from the cache. As you'll see a little further along in this article, this feature can improve performance by several orders of magnitude.
Monitor PHP application errors: Another key feature of Zend Server is its ability to collect PHP alerts and exceptions and display them in a single, central location: the Monitor → Dashboard page. This feature is of particular benefit in typical corporate environments, as it provides immediate notification of worrying server events (for example, excessive memory usage) and makes it possible to take corrective action. Administrators can also set up custom "watch rules" for the event monitor using the Rule Management → Monitoring page. However, this event monitoring feature is not available in Zend Server CE.
Change the server administration password: The Administration page offers a simple interface to set a new administrator password for Zend Server, update license details and update Zend Server itself.
Accessing Oracle Databases with Zend Server
As noted earlier, Zend Server comes with built-in support for Oracle Database. This means that once the server is installed, you can immediately start writing Oracle-backed applications with PHP using either the OCI8 or PDO_OCI extensions. Let's see this in action, by filling an Oracle Database table with some example data, and then writing a PHP script that uses the Oracle Call Interface and PHP's OCI8 extension to retrieve this data and present it as a Web page.
To begin, log in to Oracle Database as the system administrator, and create a new user account:
shell> sqlplus / as sysdba
SQL*Plus: Release 11.1.0.6.0 - Production on Thu May 21 07:29:18 2009
Copyright (c) 1982, 2007, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Release 11.1.0.6.0 - Production
SQL> CREATE USER john IDENTIFIED BY doe;
User created.
SQL> GRANT CREATE SESSION
2 , CREATE TABLE
3 , CREATE PROCEDURE
4 , CREATE SEQUENCE
5 , CREATE TRIGGER
6 , CREATE VIEW
7 , CREATE SYNONYM
8 , ALTER SESSION TO john;
Grant succeeded.
Then, connect as that user and create a new table:
shell> sqlplus
SQL*Plus: Release 11.1.0.6.0 - Production on Thu May 21 07:29:18 2009
Copyright (c) 1982, 2007, Oracle. All rights reserved.
Enter user-name: john
Enter password: ***
Connected to:
Oracle Database 11g Release 11.1.0.6.0 - Production
SQL> CREATE TABLE CITIES (
2 CITY_ID NUMBER NOT NULL,
3 CITY_NAME VARCHAR2(50)
4 );
Table created.
SQL> INSERT ALL
2 INTO CITIES (CITY_ID, CITY_NAME) VALUES (1, 'Mumbai')
3 INTO CITIES (CITY_ID, CITY_NAME) VALUES (2, 'London')
4 INTO CITIES (CITY_ID, CITY_NAME) VALUES (3, 'Paris')
5 INTO CITIES (CITY_ID, CITY_NAME) VALUES (4, 'Rome')
6 SELECT * FROM dual;
4 rows created.
SQL> COMMIT;
Commit complete.
Confirm that the records were successfully inserted with a quick SELECT:
SQL> SELECT * FROM CITIES;
CITY_ID CITY_NAME
---------- --------------------------------------------------
1 Mumbai
2 London
3 Paris
4 Rome
Now, do the same thing using PHP, by creating a new PHP script and filling it with the code below (oci.php):
<html>
<head>
<style type="text/css">
table { border-collapse: collapse; }
td { border: solid 1px black; padding: 3px; }
</style>
</head>
<body>
<h2>Cities</h2>
<?php
// open database connection
$db = oci_connect('john', 'doe', '//achilles/orcl');
if (!$db) {
trigger_error('Unable to connect to database', E_USER_ERROR);
}
// formulate and parse query
$sql = 'SELECT * FROM CITIES';
$stmt = oci_parse($db, $sql);
// execute query
oci_execute($stmt);
// iterate over result set
$count = 0;
echo '<table>';
while ($row = oci_fetch_object($stmt)) {
echo '<tr>';
echo '<td>' . $row→CITY_ID . '</td>';
echo '<td>' . $row→CITY_NAME . '</td>';
echo '</tr>';
$count++;
}
echo '</table><br/>';
echo $count . ' record(s) found.';
// close connection
oci_free_statement($stmt);
oci_close($db);
?>
</body>
</html>
This script begins by opening a connection to the database server using the oci_connect() function with the server host name 'achilles', database service 'orcl', and the user credentials. It then prepares a query with oci_parse() function, which returns a statement object; this statement object is then used to executes the query on the database server via the oci_execute() function.
A loop is used to iterate over the result set, returning individual records as objects via oci_fetch_object(). Individual fields of each record can now be accessed as object properties; it's then fairly simple to present these field values as an HTML table. Once all the records in the result set have been processed, the connection is closed with oci_close().
When you access this script through a Web browser, you should see a Web page that looks something like this:
Using Oracle Database 11g Connection Pooling
Oracle Database 11g includes a new feature aimed specifically at applications requiring high scalability: Database-Resident Connection Pooling (DRCP). DRCP makes it possible to share database connections between different application processes, resulting in more efficient use of server resources and an overall improvement in throughput. The PHP OCI8 extension (currently V1.3.5) that ships with Zend Server includes out-of-the-box support for DRCP, allowing developers to make immediate use of this feature in their PHP applications. More details on PHP and DRCP can be found here.
To enable DRCP in Oracle, log in to the database server and start up the connection pool:
shell> sqlplus / as sysdba
SQL*Plus: Release 11.1.0.6.0 - Production on Tue May 26 14:24:13 2009
Copyright (c) 1982, 2007, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Release 11.1.0.6.0 - Production
SQL> execute dbms_connection_pool.start_pool();
PL/SQL procedure successfully completed.
Confirm that the pool has been started by querying the special DBA_CPOOL_INFO view:
SQL> SELECT CONNECTION_POOL, STATUS, MAXSIZE
2 FROM DBA_CPOOL_INFO;
CONNECTION_POOL STATUS MAXSIZE
----------------------------------------------------------
SYS_DEFAULT_CONNECTION_POOL ACTIVE 40
Then, on the Server Setup → Directives page of the Zend Server administration console, find the OCI8 section, and set a name for the DRCP connection class used by the PHP application in the oci8.connection_class variable. This user chosen name allows for logical divisions between pooled servers for different applications:
Finally, enable your PHP application to use DRCP by adding the keyword POOLED to your oci_connect() connection string. While not mandatory, for maximum scalability it's also recommended that you replace the oci_connect() function with the oci_pconnect() function. As an example, here's the previous example, revised to use DRCP (drcp.php):
<html>
<head>
<style type="text/css">
table { border-collapse: collapse; }
td { border: solid 1px black; padding: 3px; }
</style>
</head>
<body>
<h2>Cities</h2>
<?php
// open database connection
$db = oci_pconnect('john', 'doe', '//achilles/orcl:POOLED');
if (!$db) {
trigger_error('Unable to connect to database', E_USER_ERROR);
}
// formulate and parse query
$sql = 'SELECT * FROM CITIES';
$stmt = oci_parse($db, $sql);
// execute query
oci_execute($stmt);
// iterate over result set
$count = 0;
echo '<table>';
while ($row = oci_fetch_object($stmt)) {
echo '<tr>';
echo '<td>' . $row→CITY_ID . '</td>';
echo '<td>' . $row→CITY_NAME . '</td>';
echo '</tr>';
$count++;
}
echo '</table><br/>';
echo $count . ' record(s) found.';
// close connection
oci_free_statement($stmt);
oci_close($db);
?>
</body>
</html>
The only change is the connection call. No application changes are needed.
You can also specify that server connections should be pooled via the $ORACLE_HOME/network/admin/tnsnames.ora file, as in the example below:
ORCL =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = achilles)(PORT = 1521))
(CONNECT_DATA =
(SERVER = POOLED)
(SERVICE_NAME = orcl)
)
)
Your connection call would then look like:
$db = oci_pconnect('john', 'doe', 'ORCL');
Note DRCP is not usable from Mac OS X, which does not yet have Oracle 11g libraries and in any case, the commercial version of Zend Server isn't supported on Mac OS X either.
Using the Zend Page Cache
One of the most important performance improvement features built into Zend Server is the Zend Page Cache, which provides URL-based caching of HTML output. Applications that dynamically generate HTML pages using PHP code benefit the most from this feature, as retrieving cached output from the Zend Page Cache is significantly faster than having PHP dynamically regenerate the same page on each new request.
The Zend Page Cache can be enabled through the Zend Server administration console, and makes use of regular expressions to match and identify URLs to be cached. This feature is entirely server-based; no changes are required to the application code to enable it.
To illustrate how it works, let's try benchmarking a popular open-source application with Zend Server: phpBB, a sophisticated PHP-based bulletin board that works with various database systems, including Oracle. phpBB can be freely downloaded from its official Web site, and comes with an automated installer that lets you get it up and running with minimal effort. The following discussion assumes that you have already configured and installed phpBB; detailed instructions for how to accomplish this can be found in the phpBB Quick Start Guide.
Assuming you've got it all set up, log in to the phpBB Administration Control Panel.
Now, create a new forum (Forums → Manage Forums). Remember to copy forum permissions from the default (example) forum so that the new forum appears in the main board index page.
Repeat this process until you have 5-6 new forums.
Now, when you visit the main board index page, you should see your newly-added forums.
This index page is dynamically generated by PHP, which queries the Oracle database server, retrieves a list of forums, and formats the result into HTML on each request. Note down the URL of this page, you'll need it a little further along.
The next step is to analyze the quantitative benefit of the Zend Page Cache with the ApacheBench monitoring tool. ApacheBench is included as part of every Apache Web server installation; you can read more about it here (httpd.apache.org/docs/2.0/programs/ab.html) First, visit the Server Setup → Components page of the Zend Server administration console and turn off Zend Page Cache and Zend Optimizer+. Remember to restart Zend Server to have the changes take effect.
Then, use ApacheBench to generate a benchmark of server response times, by sending multiple simultaneous requests for the forum index page using the URL from the previous step. Here's the output for 500 requests, sent 10 at a time:
shell> ab -n 500 -c 10 http://192.168.1.3/phpBB3/index.php
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 192.168.1.3 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Finished 500 requests
Server Software: Apache/2.2.9
Server Hostname: 192.168.1.3
Server Port: 80
Document Path: /phpBB3/index.php
Document Length: 14021 bytes
Concurrency Level: 10
Time taken for tests: 84.376 seconds
Complete requests: 500
Failed requests: 0
Write errors: 0
Total transferred: 7305000 bytes
HTML transferred: 7010500 bytes
Requests per second: 5.93 [#/sec] (mean)
Time per request: 1687.512 [ms] (mean)
Time per request: 168.751 [ms] (mean, across all concurrent requests)
Transfer rate: 84.55 [Kbytes/sec] received
Now, go back to the Server Setup → Components page of the Zend Server administration console and turn on the Zend Page Cache. Set up a new caching rule for the forum index page URL, as below:
Restart PHP to have your changes take effect, and then try running ApacheBench again with the same parameters as earlier:
shell> ab -n 500 -c 10 http://192.168.1.3/phpBB3/index.php
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 192.168.1.3 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Finished 500 requests
Server Software: Apache/2.2.9
Server Hostname: 192.168.1.3
Server Port: 80
Document Path: /phpBB3/index.php
Document Length: 14018 bytes
Concurrency Level: 10
Time taken for tests: 11.625 seconds
Complete requests: 500
Failed requests: 0
Write errors: 0
Total transferred: 7230000 bytes
HTML transferred: 7079070 bytes
Requests per second: 43.01 [#/sec] (mean)
Time per request: 232.502 [ms] (mean)
Time per request: 23.250 [ms] (mean, across all concurrent requests)
Transfer rate: 607.35 [Kbytes/sec] received
Compare the output of this run with the previous one, and you'll see that using the Zend Page Cache has reduced the time per request from 1687 ms to 232 ms! The server is able to handle many more requests/second, up from 6 to 43.
Now, go back to the Server Setup -> Components page of the Zend Server administration console and turn on the Zend Optimizer+. Then, restart PHP and give ApacheBench another whirl:
shell> ab -n 500 -c 10 http://192.168.1.3/phpBB3/index.php
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 192.168.1.3 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Finished 500 requests
Server Software: Apache/2.2.9
Server Hostname: 192.168.1.3
Server Port: 80
Document Path: /phpBB3/index.php
Document Length: 14018 bytes
Concurrency Level: 10
Time taken for tests: 6.706 seconds
Complete requests: 500
Failed requests: 0
Write errors: 0
Total transferred: 7230000 bytes
HTML transferred: 7079070 bytes
Requests per second: 74.55 [#/sec] (mean)
Time per request: 134.130 [ms] (mean)
Time per request: 13.413 [ms] (mean, across all concurrent requests)
Transfer rate: 1052.79 [Kbytes/sec] received
It should be clear that Zend Optimizer+ improves performance even further, with the average time per request now dropping to 134 ms, and the server now able to handle 74 transactions/second. Compare that with the initial run, and you'll see that just turning on these two components (with no additional fine-tuning or code optimization needed) produces a significant improvement in performance.
Conclusion
As the above examples show, Zend Server is a stable and secure PHP stack that works with Oracle out of the box, making it easy to develop and deploy Oracle+PHP applications in an enterprise environment. A powerful and flexible caching engine, a browser-based administration console and built-in support for recent Oracle innovations such as Database Resident Connection Pooling round out the package, making this a good alternative for anyone who's ever needed to deploy a PHP application server with an Oracle-based infrastructure.
Vikram Vaswani is the founder and CEO of Melonfire,
a consultancy firm with special expertise in open-source tools and
technologies. He is the author of four books on PHP and MySQL, and a frequent contributor to Zend
Developer Zone, IBM DeveloperWorks, and other community sites.
Copyright 2009 Zend Technologies. Published by Permission.
|