Zend Server CE is the Community Edition of the PHP application server by Zend Technologies. It’s a free environment that can be used to run PHP applications using additional features compared to the PHP.net version. Some of these features are:

  • Zend Optimizer+, a PHP byte code accelerator;
  • Zend Data Cache, a data caching system for PHP.

Using the Zend Optimizer+ we can speed up the execution of a PHP application without any change on the code. Basically the Optimizer+ is a caching system for the bytecode generated from the PHP interpreter.
The Zend Data Cache is a caching system for PHP and can be used to cache variables, objects, etc. This means that you have to modify your code to use this cache. However, the change of the PHP code is very simple and limited. For more info about the Zend Data Cache we suggest to read the White Paper “A pratical guide to data caching with Zend Server” of Shahar Evron, Product Manager of Zend Technologies.

Basically using Zend Server CE we can speed up the execution of a PHP application but the question is how much faster? The answer depends on the PHP application and compared with what?
In this post I run a benchmark of Joomla, the famous CMS written in PHP, using Zend Server CE vs. APC and Memcached. To run this benchmark I worked together with Renato Salvatori of Cost, an IT company specialized in Joomla.

In details, we run the benchmark into two phases:

  1. using the Zend Optimizer+ of Zend Server CE vs. APC;
  2. using the caching mechanism of Joomla on the following backends: File, Memcached, APC and Zend Server CE (using File and Shared Memory).

In order to use the Joomla caching with Zend Server we used a plugin written by me and Renato Salvatori, you can download it below in the post.

Benchmark methodology

We used the default installation of Joomla 1.5.17 using the example data for the content of the site. We tested the home page of Joomla using Apache Benchmark (ab) with 100 requestes and 10 concurrency users (-n 100 -c 10). We run each experiment 6 times and we took the average of the results. We measured the time per request (mean across all the concurrent requests in ms) and the transfer rate (Kbyte/sec).

All the experiments reported in this post have been executed using a CPU Intel Core 2 at 2.10 Ghz with 2 GB of RAM running Gnu/Linux OS with kernel 2.6.28 . We used the following software configuration: Zend Server 5 CE, Apache 2.2.11, PHP 5.3.2, Joomla 1.5.17, Memcached 1.4.5, APC 3.1.3p1, MySQL 5.0.45.


APC vs Zend Optimizer+

In the first step of the experiment we run the benchmark with the caching of Joomla disabled. We tested the response time of the home page with and without the bytecode accelerator of Zend Optimizer+ and APC. We reported the results in Table 1.


time per request, mean across all concurrent requests (ms) transfer rate (Kbyte/sec)
No Cache, No Optimizer+, No APC 114,017 286,87
No Cache, APC 80,135 408,27
No Cache, Optimizer+ 71,019 460,70

Table 1: Response times of Joomla using PHP accelerators


The results show that Zend Optimizer+ is the faster one. Using Zend Server 5 CE Joomla runs 60% faster of the PHP.net (with no accelerator) and 13% faster of APC. We reported the transfer rate of the results in Figure 1 (high value means better performance).

figure1

Figure 1: Transfer rate (Kbyte/sec)

Data cache experiment

In the second step of the experiment we run the benchmark using the caching plugins of Joomla on the following caching systems: File, APC, Memcached, Zend Server CE (file), Zend Server CE (shared memory). We split the experiment into two steps: the first using the APC byte code accelerator, and the second using the Zend Optimizer+ code accelerator. Below we reported the results of this experiment (Table 2 and 3).


time per request, mean across all concurrent requests (ms) transfer rate (Kbyte/sec)
Cache: File 53,383 612,91
Cache: APC 49,275 664,23
Cache: Memcached 50,507 647,73
Cache: ZendServer file 51,541 634,51
Cache: ZendServer shm 46,527 703,50

Table 2: Results with APC enabled, and Zend Optimizer+ disabled

As you can see the best result, in term of performance, comes with the usage of Zend Server CE (with shared memory caching system, shm). Zend Server CE is 14% faster than File, 9% faster than Memcached, and 6% faster than APC.


time per request, mean across all concurrent requests (ms) transfer rate (Kbyte/sec)
Cache: File 40,716 803,54
Cache: APC 38,898 841,13
Cache: Memcached 39,058 837,90
Cache: ZendServer file 39,102 836,95
Cache: ZendServer shm 36,531 895,79

Table 3: Results with APC disabled, Zend Optimizer+ enabled

The same results comes with Zend Optimizer+ enabled and APC disabled. The faster caching system is Zend Server CE with shared memory. Zend Server CE is 11% faster than File, 7% faster than Memcached, and 6% faster than APC.

If we compare the data cache results using APC or Zend Optimizer+ we discover that the best results comes with Zend Optimizer+, the data caching system of Joomla runs faster of 35% compared with APC (Figure 2, high value means better performance).

figure2

Figure 2: Transfer rate (Kbyte/sec)

Summarizing, using the Zend Optimizer+ and the Data Cache of Zend Server CE you can speed up the execution of Joomla from 60% to 300% compared with PHP.net (with no accelerator) and from 13% to 35% compared with APC.

The Joomla caching plugin for Zend Server CE

In order to use the data caching of Zend Server CE with Joomla you have to install the plugin joomla_zendserver.zip. You can download it here.

The installation of this new plugin is very easy, you have only to unpack the zendserver.tar.gz file and copy the files zendserver_disk.php and zendserver_shm.php in the folder libraries/joomla/cache/storage/ of Joomla.

After that you can choose the cache handler Zendserver_disk and Zendserver_shm from the System tab of the Global Configuration menu of the Administration interface of Joomla. That’s it!

Conclusion

In this post we showed that Zend Server CE is the faster PHP stack to run Joomla applications. The benefits, in term of performance, are great: up to 35% faster of APC and up to 300% of PHP.net (with no accelerators).

If you are interested in other benchmarks of Zend Server CE you can read the White Paper “Optimizing Drupal Performance” by Acquia and Zend Technologies.

In the future, I would like to run more benchmarks on Zend Server CE using other PHP open source softwares. If you have any proposals please add a comment, thanks.

If you have a PHP application that use session data and you want to scale using multiple servers or build a reliable architecture you have to share the session data between all the servers in some ways. One of the easy way to do that is to use a load balancer to distribute the traffic between multiple servers and use a database to share the session data.

In the open source community there are many examples on how to share session data using database but i didn’t found an example using MS SQL Server with the new Microsoft SQL Server Driver for PHP so I decided to write a new session handler from scratch. I used the last version 1.1 of the Microsoft SQL Server Driver. I tested the session handler using two Windows Server 2003 running IIS6 and Zend Server 5 CE. I used a SQL Server 2005 database to share the PHP session between the two servers (see diagram below).

diagram

The custom session handler

I built a PHP class named SQLSrv_Session with the following static methods: open, close, read, write, destroy, and gc (garbage collector). Basically these are the methods that you have to provide to built a custom PHP session handler (see the session_set_save_handler function of PHP for more info). For security reasons I provided a method (sqlsrv_escape) to escape the session data to write in the MS SQL Server. After the definition of the class I used the register_shutdown_function of PHP to call the session_write_close. This is a fix for a issue of the PHP session manager as of PHP 5.0.5 (see the comments on the pgp.net page of session_set_save_handler). Finally, in order to change the default session handler to the SQLSrv_Session I used the session_set_save_handler as follow:

1
2
3
4
5
6
7
ini_set('session.save_handler', 'user');
session_set_save_handler(array('SQLSrv_Session', 'open'),
                         array('SQLSrv_Session', 'close'),
                         array('SQLSrv_Session', 'read'),
                         array('SQLSrv_Session', 'write'),
                         array('SQLSrv_Session', 'destroy'),
                         array('SQLSrv_Session', 'gc'));

In this way we configure PHP to use a custom session handler (user) and choose the new methods of the session manager.
If you want to use the SQLSrv_Session handler you have to include the SQLSrv_Session.php in of all of your scripts (i suggest to use require_once “SQLSrv_Session.php”; at the beginning of your PHP scripts).
After that you can use the PHP session as usual using the $_SESSION global variable. The PHP session manager will use the SQLSrv_Session class to manage the session data instead of the default one.

Installation

In order to use this custom session handler you have to enable the sqlsrv extension from the Zend Server web interface (or in the php.ini if you are a fan of the old school). To manage PHP extensions using Zend Server is very simple, you can do everything using the web interface, under the menu Server Setup > Extensions. You can Turn on the extension with a click and restart the PHP environment with another click on the button Restart PHP, located at the bottom of the page.
To use the sqlsrv extension ver. 1.1 you must have installed the Microsoft SQL Server 2008 Native Client. You can check the system requirements of the SQL Server Driver for PHP here.

After that, to start to use the custom session handler you have to create a database in your MS SQL Server to store the session data.
This database will contain one table with the following structure:

session_id VARCHAR(32) as primary key
session_value VARCHAR(MAX) NULL
updated_on DATETIME not NULL

To configure the SQLSrv_Session class to use the table created in the previous step you have to use the following constants: DB_HOST, DB_USER, DB_PASS, DB_NAME, and DB_SESSION_TABLE. After that you will be able to use the custom session handler.

Testing

In the .zip attached in this post you can find a simple PHP script to test the custom session handler. This script basically try to use the session handler storing some random values into the $_SESSION. You can check the data stored in your SQL Server database to see if all is working good. To test the destroy method of the custom session handler you have to call the test.php?destroy (passing the destroy parameter in the URL).
Please let me be clear on this point, I provided only some test on this class and I used it only in a simple PHP scenario. If you are planning to use this code on a production environment you have to provide a complete test on your application. However I will be happy to help you if you will find issue using this class, so please comment this post.

Performance consideration

The solution provided in this post is very simple, easy to install and manage, these are its advantages. If your PHP application is used in an high traffic scenario and you need performance this solution is not good enough. It’s a well known fact that share session data using a database is not so fast, there are better ways to do that. For instance, using Memcached to share data in memory or using the Session Cluster of Zend Server 5, especially for business critical scenarios. However, if you are looking for an easy and cheapest solution to share PHP session between multiples IIS servers, using MS SQL Server, this can be actually a good solution for you.

Special thanks

I would like to thanks Gobal Deva to helping me to test the SQLSrv_Session class.

Download

SQLSrv_Session.zip


Recently I started to develop on IBM i5 systems using PHP. PHP is becoming a very popular languages in the IBM i5 community to produce web applications and to modernize “green screen” applications. If you want to know how to use PHP on IBM i5 systems you have to look at the Zend Core for i5, the PHP distribution of Zend Technologies.

Zend Core for i5/OS provides the i5 Toolkit for PHP, an API system to call i5 functionalities from PHP. One of the function of this API is the i5_spool that is able to manage spool files for specific i5 users. In this post I present a class to convert a spool file in PDF using the Zend_Pdf class of the Zend Framework.

The class is the i5Spool and you can download it here.

You can easly convert a spool file in PDF choosing the page format, the page margins, the font type, the font size, the interline, etc.
Here an example of usage:

1
2
3
4
5
6
7
8
9
10
11
12
require_once 'i5Spool.php';
$spool= new i5Spool('host','username','password');
$sp = array (	
	'JOBNAME' => 'QPADEV0012',
	'SPLFNAME' => 'QPJOBLOG',
	'SPLFNBR' => 3,
	'USERNAME' => 'ENRICO',
	'JOBNBR' => '697478'
);
header("Content-Disposition: inline; filename=spool.pdf"); 
header("Content-type: application/x-pdf");
echo $spool->toPdf($sp);

In the line 2 we create an i5Spool object passing the host, username and password to connect to the i5 system. In order to export a spool to PDF we use the toPdf method.
We have to pass the information related to the spool file: job name (JOBNAME), job number (JOBNBR), user (USERNAME), spool name (SPLFNAME) and spool number (SPLFNBR).
The toPdf function returns a string contains the PDF so you have to print it if you want to pass to the browser (line 12).
The toPdf method has a second optional parameter, an array contains the format of the PDF page.
The format of a PDF page is composed by (the default values are reported in parenthesis):

  • page format (Zend_Pdf_Page::SIZE_A4_LANDSCAPE)
  • font type (Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_COURIER))
  • font size (9)
  • interline (9)
  • margin-left (20)
  • margin-top (20)
  • margin-bottom (20)
  • encoding (utf-8)

page_pdf

For instance if you want to change the font size, the margins and the interline you can use the follow array as second parameter of the toPdf method:

1
2
3
4
5
6
7
$format= array (
	'font-size'     => 10,
	'interline'     => 11,
	'margin-left'   => 30,
	'margin-top'    => 30,
	'margin-bottom' => 30
);

For more info about the i5 Toolkit for PHP you can visit this web page: http://files.zend.com/help/Zend-Core-i5-Help/i5_php_connector_api.htm

phpDay 2010Do you want to present a talk to the next phpDay conference in Italy? This year the conference will be the 14th-15th May 2010 in Alba Adriatica (a very nice place on the beach!).

The main topic of the conference is “PHP and quality”. Let’s go to propose you talk in english or in italian. You have time to send a proposal until the 15th of March.

The phpDay is the most important PHP conference in Italy since 2001. The conference is managed by GRUSP, the italian association of php users and developers.
For more info you can visit the web site of the GRUSP association here.

I’m reading the new book of Keith Pope, “Zend Framework 1.8, web application development” of PackT Publishing and my first impression is very good!

Zend Framework 1.8 - Web Application DevelopmentThis book introduces the Zend Framework (ZF) using a direct approach to build a real web application in depth, in particular an e-commerce web site (you can download the source code of this application from the PackT web site).
In my opinion this is a very good approach because the main difficulties when you start a new php application using the ZF and in general the MVC paradigm are: how to structure the application, where to write the code, how to build the models, etc.

I guess this is one of the first book about the new version 1.8 of ZF. As you know starting from the version 1.8 the team of ZF has introduced the Zend_Application class to easly manage the configuration and the bootstrap phase of the application using a .ini file. The usage of the Zend_Application is showed in the Chapter 3 of the book.

Especially useful is the part of Model design in the Chapter 4, where the author shows step by step how to build a model and why. For instance the author presents the Model of a Product showing the balance between the Controller and the Model, and the general rules to follow: code reuse, controller readability, maintainability, etc.

I’m glad to the author to have inserted the Chapter 12 about testing the application using PHPUnit. This is a very important part of every software developing life cycle and sometimes in the real life someone forgot to test! Me too, i’m honest :)

In conclusion I strongly suggest this book if you are interested in developing php web applications using the Zend Framework, whether you are a newbie or and experienced ZF developer.

For more information about this book you can go to the publisher web site here.

The last week i talked at the PHP Barcelona Conference 2009 about how to improve the performance of PHP applications using the Zend_Cache class of the Zend Framework.
Here you can find the slides of my talk with the PHP source code that i showed during my presentation.

Here the source code showed during the talk.

Thank you to the staff of the PHP Barcelona Conference, it was a very good international conference!

In this post i’m going to refactoring the ZF Secure Login application, that i provided in my previous post, using the new Zend_Application class, out from the version 1.8 of Zend Framework.

Here you can find the source of the new application (12 Kb)

From the Reference Guide of ZF: “Zend_Application provides a bootstrapping facility for applications which provides reusable resources, common- and module-based bootstrap classes and dependency checking. It also takes care of setting up the PHP environment and introduces autoloading by default.”

Using this class I arranged the new application with some structural changes. In particular I modified the application folder with the following directories: configs, controllers, forms, layouts, models, plugins, views.
In the configs folder i provided an application.ini where i reported all the parameters of the application.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
includePaths.library = APPLICATION_PATH "/../library"
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
resources.layout.layout = "layout"
resources.layout.layoutPath = APPLICATION_PATH "/layouts"
resources.frontController.plugins[] = "App_Plugin_SessionCheck"
resources.db.adapter = "PDO_MYSQL"
resources.db.params.host = "localhost"
resources.db.params.username = "root"
resources.db.params.password = 
resources.db.params.dbname = "zf_example"
resources.session.namespace= "SecureLogin"
auth.active= on
auth.timeout= 60
password.salt= "df7hsKJ3284sdhfj33BC"
 
[staging : production]
 
[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
 
[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

As you can see the application.ini is splitted into 4 different sections: production, staging, testing and development.
These sections are related to the different scenarios where to run the application.
In the production section you can find all the configuration data of the application, like the db parameters, the name of the bootstrap class, the layout path and the frontControllers plugin, etc (in this case the plugin is the SessionCheck that I used in the Initializer class of the previous architecture).

For the folders: controllers, layouts, models and views I provided the same structure of the previous architecture. So nothing is changed in their files.
The new two directories are forms and plugins. In the forms folder I provided an App_Form_Login class to manage the login Zend_Form. In the plugins folder I put the front controller plugin, named App_Plugin_SessionCheck, to manage the authentication.
In the previous architecture of the project i used the plugin Initializer with the method checkSession.
As you can notice almost all the classes of the application starts with App_ to indicate the applications folder. This looks much better for maintenance reason, to reach the classes more easly.

So basically the main difference of this new application, from an architectural point of view, are represented by the folder application, with the subfolder configs, forms and plugins.
The other differences are in the bootstrap phase. In this application the public index.php contains the following source:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
 
// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));
 
// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/../library'),
    get_include_path(),
)));
 
/** Zend_Application */
require_once 'Zend/Application.php';  
 
// Create application, bootstrap, and run
$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/application.ini'
);
$application->bootstrap()
            ->run();

Basically an include path and an instance of the Zend_Application class with the application.ini to be used.
The other main difference is rappresented by the Bootstrap.php file located under the application folder.
This file contains the following source:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
    protected function _initModuleAutoloader ()
    {
        $al = new Zend_Application_Module_Autoloader(array('namespace' => 'App' , 'basePath' => dirname(__FILE__)));
    }
    protected function _initView ()
    {
        // Initialize view
        $view = new Zend_View();
        $view->doctype('XHTML1_STRICT');
        $view->headTitle('ZF Secure Login');
        // Add it to the ViewRenderer
        $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');
        $viewRenderer->setView($view);
        // Return it, so that it can be stored by the bootstrap
        return $view;
    }
 
    protected function _initSession ()
    {
        $options = $this->getOptions();
        $session = new Zend_Session_Namespace($options['resources']['session']['namespace']);
        Zend_Registry::set('session', $session);
    }
 
}

Here we defined the view structure of the application and the initialization of the Session.
With this new architecture all the resources, accross different classes, can be accessed using the Zend_Registry class.
We don’t use the Globals.php class anymore. This class, in the previuos architecture, contained the singletons entities used along all the application classes. I discovered that using a Global class you can become crazy to provide Unit Testing and in general to debug an application.

To reach the configuration data, from a controller, I used the method getInvokeArg(’bootstrap’)->getOptions(), for instance in the loginAction of the IndexController I retrieved the value of the auth.timeout of the application.ini using this piece of code:

1
2
$options= $this->getInvokeArg('bootstrap')->getOptions();
$this->view->form = new App_Form_Login($options['auth']['timeout']);

Moreover in this new application I simplify the security using the rand auto value of the token in the Zend_Form_Element_Hash. I used only a single salt value to improve the security of the md5 password stored into the table user of the MySQL database. In this way I provided a separation from the data of the database and the application. In this case if someone breaks into the database and not the application is not able to decrypt the password stored into the db. In the previous post i used different salt for every password but i stored it into the same db table.
The passwords are stored into the database using the MySQL statement ‘MD5(CONCAT(salt,password))’ where salt is the value stored into the password.salt of application.ini and password is the plain text of the password to store.

In conclusion the new application, using the Zend_Application class, seems to be much more structured, much more configurable with the use of the application.ini file, and last but not least we have to write less code, and this is the best part for a developer :)

One of the features of the Zend Platform is the Job Queue, a server application that is able to schedule and manage the execution of php scripts (jobs).

The Job Queue can be used to create asyncronous execution of php script and provide, for instance, the scalability of a server application (for more info read the White Paper “Scalability and Responsiveness with Zend Platform’s Job Queue” by Dotan Perry and Shie Erlich).

You can manage the Job Queue feature of the Zend Platform with a web interface (see the figure below) or directly in PHP with an API system.

job_queue

Using the web interface you can schedule the execution of a job (a php script) that is located into the JobQueue directory of the Zend Platform (the default is /usr/local/Zend/Platform/JobQueue in a Linux environment). You can also suspend and resume jobs from the queue, view the statistic of the job queue, view the history of each job execution and setting the parameter of the queue (maximal queue depth, maximal re-queue times, queue alias, scripts folder, etc).

As I said you can use the job queue also from PHP with the use of a API system. Basically the Job Queue Zend API contains two main classes to manage the connection to a queue server and to schedule the execution of jobs. This classes are ZendAPI_Queue and ZendAPI_Job. Is very easy to use this API and you can schedule the execution of your php script in a few lines of code. Let me show this introducing some examples.

In order to connect to a queue server you have to specify the host:port address and the password of the queue server (the default port of the queue server is 10003). Here there is an example:

1
2
3
4
$queue= new ZendAPI_Queue('192.168.1.10:10003');
if ((empty($queue)) || (!$queue->login('password'))) {
    throw new Exception('Error on queue connection');
}

When you have established a connection you can manage the scheduling of a job. For instance here we scheduled the execution of a job named send_email.php for the next 4 hours.

1
2
3
$job = new ZendApi_Job("send_email.php");
$job->setScheduledTime(time() + 4*3600);
$id = $queue->addJob($job);

If you want to search for a job into a queue server you can use the getJobsInQueue method of the ZendAPI_Queue class.
For instance you can remove the failed jobs from a queue server with the following code:

1
2
3
4
5
6
7
8
9
10
$queue= new ZendAPI_Queue('192.168.1.10:10003');
if ((empty($queue)) || (!$queue->login('password'))) {
    throw new Exception('Error on queue connection');
}
$jobs_status = array(status=>JOB_QUEUE_STATUS_LOGICALLY_FAILED);
$all_failed_jobs = $queue->getJobsInQueue($jobs_status);
foreach ($all_failed_jobs as $failed_job) {
      echo "removing job $failed_job from queue...";
      $queue->removeJob($failed_job);
}

In this post i introduced only the main functions of the Job Queue Zend API, for the complete list you can read the User Guide of Zend Platform 3.6 at pag. 295-305.
In my opinion using the Job Queue feature of the Zend Platform you can explore a new way to think about web solutions with asyncronous execution of PHP code.

Today i created an example in PHP to display data into a Google map. I used my GMaps class (see my previous post) to retrieve geographic information for all the provinces of Italy, as you know i’m italian. I inserted all the data into a table of MySQL with the following fields: id, province, code, area, latitude, and longitude where code is the italian automobile code and area is the name of the region. For instance the province of Pescara has the following record: 69,’Pescara’,'PE’, ‘Abruzzi’, 42.4648, 14.2141.

Provinces of Italy



The example in PHP uses this database to display the geographic data of all the provinces of Italy. You can select the geographic area (region) in a combobox and display the data on a Google Map.

You can download the source code of the example with the database here.

Click here to see the online example.

About this blog

This is my personal blog about computer programming in PHP for business and passion. I'm Enrico Zimuel a Software Engineer since 1996. I work as Senior Consultant & Architect at Zend Technologies. For more info about me visit my web site.

PHP 5 Zend Certified Engineer Zend Framework Certified Enginner

My next conference


WebTech Conference 2010
follow me on twitter