What You See Is What You Get Element

Build an Enterprise-Grade PHP Stack with Zend Server and Oracle Database

By Vikram Vaswani

The quick way to create an Oracle/PHP/Apache/Linux (OPAL) development and deployment environment

Updated March 2014
 

Downloads:

Zend Server

Contents

Introducing Zend Server

Getting Familiar with the Zend Server Dashboard

Working with Applications

Using Oracle Database with Zend Server

Using Connection Pools in Oracle Database

Improving Performance with Page and Opcode Caching

Logging and Analyzing Bottlenecks and Errors

Conclusion

Introduction

If you're building an application that's going to roll out at enterprise scale, chances are that you're already using Oracle as your database back-end. And for your application's Web front-end, there's no better choice than PHP: after all, it's easy to learn, popular for building Web apps, has an active community and good documentation, and comes with support for a bunch of databases, including Oracle.

Now, where do you get started? If you like doing things the hard way, you can download Apache and PHP, compile PHP as an Apache module, compile Oracle's OCI8 database extension for PHP, then configure and hook it all together to create a custom Oracle/PHP/Apache/Linux (OPAL) stack. But rolling your own stack also means that you don't have anyone to call when you need support. If you don't have time to experiment, or if you prefer to focus on building your application instead of dealing with infrastructure issues, Zend Server can help.

Zend Server is a ready-to-run PHP stack that works on Windows, Linux, Mac OS X and IBM i. It comes with built-in support for Oracle databases, making it quick and easy to develop Oracle-backed Web applications. Plus, it's got a bunch of additional tools for continuous integration, release automation, application monitoring and performance management, giving you a high-performance foundation for enterprise OPAL application development and deployment. Keep reading, and I'll show you a few examples of how you can use it.

Introducing Zend Server

Zend Server makes it easy to get started with PHP for rapid, agile application development and deployment.

  • For developers, it includes updated, fully-tested and supported versions of PHP 5.5 and Apache 2.4, support for multiple database products, including Oracle (via the OCI8 extension) and MySQL, and Zend-specific add-ons for error detection, packaging, deployment and versioning. On Linux, Zend Server also lets you use nginx as an alternative to Apache.

  • For administrators, it provides an installable, enterprise-ready and supported middleware stack with centralized application monitoring and performance tracking. Access control and provisioning make it possible to enforce consistent security policies, and scaling and session clustering let administrators add new servers to support higher loads.

If you’re reasonably experienced with PHP and are happy to maintain the server and manage updates manually, you can opt for the free version of Zend Server. This version doesn’t include the page caching, code tracing, offline job queuing, session clustering and cloud scaling features or the long-term support for PHP that are included with the commercial versions.

If these features are important to you – and they should be if you’re deploying business-critical PHP applications – then you should consider purchasing one of the commercial versions of Zend Server, which entitle you to some or all (depending on the version purchased) of the above features including security hotfixes and technical support for PHP from Zend.

Now that you know what Zend Server's all about, let's take it for a test drive. But before we begin, a few housekeeping items:

  • I'll assume that you know the basics of PHP scripting. In case you don't, this beginner series should get you up to speed. I'll also assume that you know the basics of working with Oracle databases and SQL.

  • I'll assume that you have a working copy of Oracle VirtualBox and you've downloaded and extracted the Zend Server VirtualBox appliance. This appliance provides pre-configured instances of Zend Server 6.3 and Oracle Database XE 11.2 running on Oracle Linux 6.4.

The VirtualBox appliance includes a 7-day trial of Zend Server Enterprise Edition which can easily be extended an additional three weeks, so you can check out all the features in action and decide which ones are most important to you. The appliance makes it easy for you to quickly get started with understanding the combination of Zend Server, PHP and Oracle; it's used for all the examples in this article.

If you already have a working development or production environment and you'd like to add Zend Server to it, you can instead read the detailed instructions for standalone installation on Linux (DEB and RPM packages), Windows and Mac OS X.

Getting Familiar with the Zend Server Dashboard

To begin, you'll need to fire up VirtualBox, then import the downloaded Zend Server VirtualBox appliance into it. Review and agree to the Zend Software License Agreement, then adjust memory, disk and CPU settings for the newly-created virtual machine and start it up. In case of problems, read more on getting started with the VirtualBox appliance.

Once you've started up the virtual machine, Zend Server will be automatically downloaded and installed to it (this might take a few minutes). Once this is done, you'll be dropped to a Linux login prompt, from where you can log in as 'guest' with password 'guest1234'. Once you're on the virtual desktop, access Zend Server by launching a browser and pointing it to the URL http://localhost:10081/ZendServer.

The first time you try accessing Zend Server, it will prompt you to accept the license, choose a working environment ('Development' is a good choice for this article) and enter an administrator password, as shown below:

image11-png

Password entry

Enter the requested information, click your way through the next couple of screens and you’ll be transferred to the Zend Server welcome page as below:

image10-jpg

Welcome page

The Zend Server welcome page provides an overview of the different things you can do: deploy sample applications, read getting started instructions, watch introductory videos, or download Zend's Continuous Delivery Blueprint. Clicking Overview -> Dashboard takes you to the Zend Server Dashboard, which is the operational centre of Zend Server. Here's a quick overview of what each Dashboard section does:

The Overview section is where you head when you want to be Big Brother: it contains all of Zend Server's monitoring functions, allowing you to view events, recent errors, and statistics for resource usage and performance. Detailed information on the current PHP build and installed components can be obtained from the Overview -> Server Info page, and there's a running update of important log files at Overview -> Logs.

image06-png

Server information

Next up, the Applications section. I'll discuss applications in depth further along so, for the moment, just know that this section is the primary control point for deploying and managing new PHP applications on the server. It's also where you can control virtual hosts, set up per-application monitoring and caching rules and schedule jobs.

image19-png

Applications

The Configuration section is all about PHP and server configuration. You can turn PHP extensions on or off, activate or deactivate Zend's performance and diagnosis tools, and enable local and remote PHP debugging and profiling of Web applications with Zend's PHP IDE. If you're managing a cluster of PHP application servers, this is also where you can configure distributed session management.

image00-png

PHP configuration

The Administration section is where you go when you want to manage cluster servers, users and passwords; view audit trails; update your license; or configure general settings for logging, email notifications and error reporting. Interestingly, Zend Server has a Web API for executing any of its features from outside the browser-based admin interface; you can manage your API keys at Administration -> WebAPI.

image01-png

User audit trails

Working with Applications

When it comes to deploying PHP applications, it often seems like every developer has a different approach: Composer, rsync, Phing, Ant, PEAR, or any number of home-brewed solutions. This results in inconsistent workflows and added maintenance and troubleshooting overhead for Ops teams. In many cases, automated solutions aren't even considered; deployment is an entirely manual process, resulting in hard-to-track errors and misconfiguration if steps are accidentally skipped.

Zend Server attempts to streamline this, by treating applications as discrete, logical units that can be defined, deployed and analyzed using a centralized management interface. There are two ways to go about this. You can package your applications using the ZPK format and deploy them using Zend Server; Zend Server will automatically recognize each ZPK as a separate application. Or, if you already have existing applications in place or use a different build/packaging system, you can manually define application entries in Zend Server using their base URL.

There are quite a few advantages of following this application-centric approach. Application deployment becomes simpler and more consistent, because there's a standard format for delivering application code. Application developers can define required parameters and environment variables in advance; Zend Server automatically takes care of prompting for these parameters when the application is deployed, reducing the risk of misconfiguration. And finally, events and monitoring rules can be defined per-application, making it easy to identify which applications need attention when operating clusters hosting multiple applications.

Zend Server 6.3 includes a number of popular PHP applications in ZPK packaging, including Wordpress, Magento and Drupal. I'll show you an example of deploying one of them further along in the article. For the moment, let's begin by defining an existing server URL as an application. First, open a terminal window and login as 'root' (the password is 'zend1234'). Then create an opal directory in the server's web document root (/var/www/html by default) and add the following simple PHP script to it:

/var/www/html/opal/index.php:

<?php

echo 'Hello from Zend Server and PHP ' . phpversion();

?>

It's not very impressive, but don't worry, we'll add a few bells and whistles soon. For now, the next step is to tell Zend Server to treat this newly-created directory as a separate application. So, click through to Applications -> Apps -> Define Application and define a new application, by providing an application name ('My OPAL App') and base URL ('/opal').

image12-png

Application definition

The newly defined application should now be displayed on the Applications -> Apps page.

image15-png

Application deployment

Using Oracle Database with Zend Server

In addition to a working Zend Server instance, the VirtualBox appliance also includes an installation of Oracle Database 11g Express Edition ("Oracle XE") for easy testing. And since Zend Server already includes PHP's OCI8 extension, it can connect to most Oracle databases out of the box. This makes it easy to quickly start building Oracle-backed PHP applications with Zend Server.

Let’s see this in action, by unlocking Oracle XE's sample HR schema and then updating the previous PHP script to query this schema and present results as a Web page.

To begin, Oracle XE needs to be configured and started. When prompted for the root password, enter the password 'zend1234'.

shell> su -

shell> /etc/init.d/oracle-xe configure

Choose the database ports and passwords as shown in step 6 onwards in these instructions.

Log in as the 'oracle' user and set the Oracle XE environment variables.

shell> su - 

shell> su - oracle

shell> source /u01/app/oracle/product/11.2.0/xe/bin/oracle_env.sh

For more information on the above steps, refer to these additional instructions. You should now be able to log in to Oracle Database as the system administrator and unlock the HR schema and user account:

shell> sqlplus / as sysdba

SQL*Plus: Release 11.2.0.2.0 Production on Wed Feb 5 02:26:57 2014

Copyright (c) 1982, 2011, Oracle.  All rights reserved.

Connected to:

Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production

SQL> ALTER USER HR IDENTIFIED BY guessme ACCOUNT UNLOCK;

User altered.

Then, connect as the 'HR' user and run a quick query:

SQL> CONNECT hr

Enter password: ****

Connected.

SQL> SELECT FIRST_NAME, LAST_NAME, HIRE_DATE FROM EMPLOYEES;

FIRST_NAME           LAST_NAME                 HIRE_DATE

-------------------- ------------------------- ------------------

Steven               King                      17-JUN-03

Neena                Kochhar                   21-SEP-05

Lex                  De Haan                   13-JAN-01

Alexander            Hunold                    03-JAN-06

Bruce                Ernst                     21-MAY-07

...

Now, do the same thing using PHP, by updating the previous PHP script with the code below:

/var/www/html/opal/index.php:

<html>

  <head>

    <style type="text/css">

    table { border-collapse: collapse; }

    td { border: solid 1px black; padding: 3px; }

    </style>

  </head>

  <body>

  <h2>Employees</h2>

  <?php

  // open database connection

  $db = oci_connect('hr', 'guessme', 'localhost/XE');

  if (!$db) {

    trigger_error('Unable to connect to database', E_USER_ERROR);

  }

  // formulate and parse query

  $sql = 'SELECT FIRST_NAME, LAST_NAME, HIRE_DATE FROM EMPLOYEES';

  $stmt = oci_parse($db, $sql);

  // execute query

  oci_execute($stmt);

  // iterate over result set

  $count = 0;

  echo '<table>';

  while (($row = oci_fetch_object($stmt)) != false) {

    echo '<tr>';

    echo '<td>' . htmlentities($row->FIRST_NAME) . '</td>';

    echo '<td>' . htmlentities($row->LAST_NAME) . '</td>';

    echo '<td>' . htmlentities($row->HIRE_DATE) . '</td>';

    echo '</tr>';

    $count++;

  }

  echo '</table><br/>';

  echo $count . ' record(s) found.';

  // free statement handle and 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 Easy Connect syntax. It then prepares a query with the oci_parse() function, which returns a statement object; this statement object is then passed to the oci_execute() function to execute the query.

A loop iterates 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 (the URL is 'http://localhost/opal/'), you should see a Web page that looks something like this:

image08-png

Database query output

And when you visit the Zend Server Dashboard, you'll now be able to see usage statistics, errors and performance just for your new application.

image05-png

Zend Server dashboard with OPAL application statistics

Using Connection Pools in Oracle Database

Oracle Database includes Database Resident Connection Pooling (DRCP), aimed specifically at applications requiring high scalability. 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 performance. The PHP OCI8 extension 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.

To enable DRCP, log in to the database server and start up the connection pool:

shell> sqlplus / as sysdba

SQL*Plus: Release 11.2.0.2.0 Production on Wed Feb 5 03:01:23 2014

Copyright (c) 1982, 2011, Oracle.  All rights reserved.

Connected to:

Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production

SQL> execute dbms_connection_pool.start_pool();

PL/SQL procedure successfully completed.

Check 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 Configurations -> PHP 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:

image02-png

OCI8 DRCP configuration

Finally, enable your PHP application to use DRCP by adding the keyword POOLED to your oci_connect() connection string. While not mandatory, it's also recommended that you replace the oci_connect() function with the oci_pconnect() function. Here's a rewritten version of the code:

<html>

  <head>

    <style type="text/css">

    table { border-collapse: collapse; }

    td { border: solid 1px black; padding: 3px; }

    </style>

  </head>

  <body>

  <h2>Employees</h2>

  <?php

  // open database connection

  $db = oci_pconnect('hr', 'guessme', 'localhost/XE:POOLED');

  if (!$db) {

    trigger_error('Unable to connect to database', E_USER_ERROR);

  }

  // formulate and parse query

  $sql = 'SELECT FIRST_NAME, LAST_NAME, HIRE_DATE FROM EMPLOYEES';

  $stmt = oci_parse($db, $sql);

  // execute query

  oci_execute($stmt);

  // iterate over result set

  $count = 0;

  echo '<table>';

  while (($row = oci_fetch_object($stmt)) != false) {

    echo '<tr>';

    echo '<td>' . htmlentities($row->FIRST_NAME) . '</td>';

    echo '<td>' . htmlentities($row->LAST_NAME) . '</td>';

    echo '<td>' . htmlentities($row->HIRE_DATE) . '</td>';

    echo '</tr>';

    $count++;

  }

  echo '</table><br/>';

  echo $count . ' record(s) found.';

  // free statement handle and close connection

  oci_free_statement($stmt);

  oci_close($db);

  ?>

  </body>

</html>

You'll notice that the only change in the script is the revised connection call; no other modification is needed to take advantage of DRCP.

 

Improving Performance with Page and Opcode Caching

Zend Server includes two components designed specifically to improve application performance: Zend Page Cache, which provides URL-based caching of HTML output, and Zend OPcache, which pre-compiles and caches PHP code at run-time. Both these features are entirely server-based; no changes are required to the application code to enable them.

To illustrate how they work, I tried benchmarking a popular open-source application with Zend Server: phpBB3, a sophisticated PHP-based bulletin board that works with various database systems, including Oracle Database. phpBB3 can be freely downloaded from its official Web site, and comes with an automated installer.

I began by installing phpBB3 in a phpbb/ directory under the server document root and configuring it using the instructions in the phpBB3 Quick Start Guide. Then, I visited Zend Server's Applications -> Apps page and defined a new application entity for it.

image13-png

Application definition

I logged in to the phpBB3 Administration Control Panel, and created 3-4 new forums. The new forums appeared on the application's index page.

image16-png

phpBB index page

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.

My next step was to analyze the quantitative benefit of Zend Page Cache and Zend OPcache with the ApacheBench monitoring tool. First, I visited Zend Server's Configurations -> Components page, turned off Zend Page Cache and Zend OPcache, and restarted Zend Server to have the changes take effect.

image04-png

Caching components turned off

Then, I used ApacheBench to generate a baseline benchmark of server response times, by sending multiple simultaneous requests for the forum index page URL. For example, here’s the command for 500 requests, sent 10 at a time:

shell> ab -n 500 -c 10 http://192.168.1.9/phpbb/index.php

I then went back to the Configurations -> Components page, turned on Zend Page Cache,and set up a new caching rule for the index page URL, as below:

image17-png

Caching rules

After restarting Zend Server, I ran ApacheBench again with the same parameters as earlier. And then, I repeated the process, this time with Zend OPcache activated. On my sample server, here's a summary of the three benchmarks:

image14-png

Results of page and opcode caching

It should be clear that on my demo instance, Zend Page Cache increased service responsiveness by 16x, with the requests served per second jumping from 13 to 213. Add in Zend OPcache, and there was a further 4x improvement, with the server now being able to serve 980 requests per second. The average time per request also dropped significantly. In short, just turning on these two components (with no additional fine-tuning or code optimization needed) produced a significant improvement in performance.

Apart from the Zend Page Cache and Zend OPcache, Zend Server also includes a couple of other useful performance-related components:

  • The Zend Server Job Queue lets you schedule PHP scripts for later or repeated execution at specific times. This makes it easy to off-load specific tasks to non-peak hours - for example, migrating or processing database records or sending out emails - while retaining control through run-time statistics and dynamic scheduling strategies. You can configure jobs through the Zend Server administration interface.

  • The Zend Data Cache API does for data what the Zend OPcache does for bytecode: it provides a way to cache PHP data structures like objects, arrays and variables in shared memory or disk files. This reduces the need to hit the database server for every request. To use it, you'd need to set cache configuration parameters through the Zend Server administration interface, then call the appropriate API functions in your PHP code.

Logging and Analyzing Bottlenecks and Errors

Zend Server 6.3 also simplifies root cause analysis with its monitoring and code tracing features, which allows developers to examine, in minute detail, the complete execution flow of requests matching predefined rules. So, for example, you might define a rule to identify slow requests, another to identify requests resulting in uncaught exceptions, a third to catch database errors, and so on. These rules can be specified per-application or globally (applicable to all PHP scripts on the server) and for each rule, you can further specify whether to trace the code.

To see some of Zend Server's monitoring rules (and to create your own), visit the Applications -> Monitoring Rules page:

image09-jpg

Zend Server default monitoring rules

You'll see, for example, a default rule for database errors, which automatically creates an event when a database-related function generates an error. This rule tracks (among others) the oci_connect() function used in the previous example.

image18-png

Slow query rule

If you were to update the OPAL application to use invalid credentials and then try accessing it, the above rule would be triggered and you'd see an error event for the application in the Dashboard. Clicking the event record would let you view a stack trace, function data and environment and server variables.

image03-png

Database error event

When code tracing is enabled for an event, you'll get an even more granular view: a list of all the functions and methods invoked by the script, together with their return values and memory consumption (Overview -> Code Tracing). The data is presented hierarchically, making it easy to perform granular code profiling, or to drill down to the exact line of code causing an error.

Here's an example of what trace output looks like for a slow request:

image07-png

Code tracing output for a slow query

The 'Running Time' column makes it easy to identify which function calls are causing the most overhead. The trace output includes statistics for the requested script, showing how many times a particular function or method was called and providing information on execution time and memory usage.

Conclusion

As the above examples show, Zend Server's application focus makes it easier to package, configure, deploy, monitor and debug Oracle+PHP applications for DevOps teams in an enterprise environment. A powerful and flexible caching engine, built-in support for Oracle Database, easy scalability with session clustering and connection pooling round out the package, making this a good solution for deploying PHP applications with Oracle infrastructure.

About the Author

Vikram Vaswani is the founder and CEO of Melonfire, a consulting services firm with special expertise in open source tools and technologies. He is also the author of the books Zend Framework: A Beginners Guide and PHP: A Beginners Guide.

Copyright Zend Technologies, 2014. Published with Permission.