Responsive AJAX applications with COMET

PHP conference season* Multiple response AJAX requests* COMET: Multiple response AJAX request implementation* HTTP compression* Page compression delays* Avoiding mod_gzip dechunking* Apache 2.2.x with mod_deflate

- PHP conference season
Before proceeding to the main topic of this post, I would like to let you know that in October it starts the PHP Conference season, at least here in Brazil where I live.

I will be attending several conferences as a speaker, at least at those events that take place in São Paulo state. In some conferences, other reputed local PHP developers will also present their talks.

If you live nearby, or you happen to be the neighborhood during this season, you are more than welcome to come along and help supporting the local PHP community.

Here follows event schedule:

Programming Language Festival
São Paulo, October 7
I will be giving a talk representing PHP in a event on which other speakers will represent other languages such as C++, C#, Java, Python and Ruby .

PHPDay at FATEC Santos
Santos - SP, October 28
I will be giving a talk about Developing PHP Applications Web Forms using AJAX and advanced plug-ins

São Paulo, November 3 - 5
I will be giving the same talk about Developing PHP Applications Web Forms using AJAX and advanced plug-ins

I PHP Conference Brasil
São Paulo, December 1 - 2
Not yet defined, but very likely I will be giving at least one talk about "Use Case Mapping - Methodology to implement PHP Web applications departing from UML use case diagrams"

* Multiple response AJAX requests
In the latest months, I have been implementing several features that use AJAX to provide a better user interface to certain aspects of the site, such as the internal site search and the new login page:

As I explained in a past post, the AJAX implementation uses hidden inline frames (iframes) instead of XMLHttpRequest objects ...

Among other reasons to prefer iframes, those allow applications to submit a single AJAX request and return multiple response steps, eventually spaced by periods on which the server is performing a complex task.

This possibility is very good to provide progress feedback for lengthy server side operations started by AJAX requests. Progress feedback is great to let the user know what is going on, while the results of the requested operation are not ready.

For instance, consider an AJAX based chat application. An user may send a message and wait for a response. While the response does not come, it is useful to know that the other user is typing something in reply.

* COMET: Multiple response AJAX request implementation
With iframes, it becomes easy to return multiple responses to a single AJAX request. But you may ask, how does it work in practice?

I have implemented a solution based on this forms generation and validation class:

It comes with a custom input plug-in class that can submit forms using an iframe based AJAX request. This plug-in generates an iframe and special Javascript code to submit the current form without causing the current page to reload.

The form submission action can be triggered by any page event, like for instance when a link or a button is clicked. The trick is that the class temporarily switches the target of the form to the iframe, submits the form, and restores the original form target.

The server AJAX response is loaded in the iframe. The iframe has width and height set to zero . This way, the users never see whatever is loaded in the iframe.

The AJAX request is sent to the same URL of form page, except that it gets a couple of request parameters to let the forms class route the handling of the request to the AJAX form submit plug-in class.

That class output an empty HTML page with some Javascript code blocks to execute many possible types of actions like updating specific parts of the page, setting Javascript variables, redirecting the browser to another page, etc..

That code is executed once it arrives to the browser and loaded into the iframe. The AJAX class calls the PHP flush() function to make those Javascript code blocks be sent to the browser immediately. This way, it can update the browser page while the AJAX request action is still running on the server side.

I implemented this AJAX approach for the first time in December 2005 for the dynamic version linked select custom form input plug-in . It was used to update two or more linked combo inputs, retrieving alternative option groups from a database on the server side.

Then I was not aware, but apparently this kind of AJAX approach already has a new name: COMET . It was coined by Alex Russel of the Dojo toolkit project. ...

* HTTP compression
The HTTP protocol supports compression of the request input and output data. This means that, if the browser supports compression, the pages may be served in compressed format, thus taking much less data and time to send to the browser. All modern browsers support compression these days.

The use of HTTP compression is specially recommended when serving HTML pages. HTML pages usually contain a lot of redundant characters.

Well supported algorithms like gzip can achieve compression rates of 5:1 or even more. This means that a 50K HTML page, may be served using only 10K of compressed data.

If you use Apache 1.3.x versions, you can use mod_gzip module to automatically compress the pages when they are served, even if they are generated by PHP.

Apache 2.x comes with mod_deflate module built-in Apache distribution.

* Page compression delays
Page compression is great but it comes with a price. If you do not have your page previously compressed, compression adds a little more time to serve the request response. It also spends more server CPU and memory.

The PHPClasses site uses Apache 1.3.x . Therefore it uses mod_gzip to serve compressed pages. Sometime ago I noticed another delay problem caused by mod_gzip .

When you use PHP to serve dynamically generated pages, PHP generates an HTTP chunked encoding response. This is a work-around introduced with HTTP 1.1 protocol standard to tell the browser that the server does not know the length of the page, but it is sending chunks of a given length until the last chunk, which has length zero.

Since compressing small chunks of data may not be very efficient, mod_gzip does not support compressing pages of unknown length, such as those generated dynamically by PHP.

On the other hand, mod_gzip supports what is called dechunking. This means that it will buffer the whole page to be able to compress a larger chunk of data, which is usually more efficient. This is fine for common pages served by PHP scripts or any other language generating dynamic Web pages.

However, to serve AJAX requests with multiple responses as described above, dechunking is very inconvenient. It delays all response steps. The whole response is served at once to the browser only when the AJAX request action is finished on the server side.

* Avoiding mod_gzip dechunking
The solution to avoid mod_gzip dechunking is to disable compression altogether when serving AJAX responses. So, I need to tell mod_gzip to not compress AJAX responses. It should also continue to compress non-AJAX response pages.

The problem is tricky because mod_gzip has no way to know in advance which requests return an AJAX response. The solution that I used is to send an custom header from the PHP script like this:

Header('X-do-not-compress-this: yes');

Then I added a line like this to mod_gzip configuration:

mod_gzip_item_exclude rspheader "X-do-not-compress-this: yes"

This is convenient when my AJAX requests return multiple responses. If it contains a single response, dechunking is not really necessary. That is up to the application to determine. So, I added a new option to the AJAX form submit custom input class to tell to issue that header only when necessary.

* Apache 2.2.x with mod_deflate
In the case of Apache 2.2.x with mod_deflate, it never dechunks responses. So it always serves dynamic PHP pages of unknown length as a series of compressed chunks.

This seemed to be a better solution. So I considered finally upgrading to Apache 2.x . However, after looking around for experiences of using PHP with Apache 2.x on busy sites, I felt a little discouraged.

It seems the major problem is that there is no static module version of PHP for Apache 2.x . This means PHP will run somewhat slower on Apache 2.x than with Apache 1.3.x with static mod_php.

I do not know why Apache 2.x cannot be built with static mod_php, but it certainly imposes significant performance loss for busy sites. This post by PHP core developer Ilia Alshanetsky clearly shows the problem, despite it is almost 2 years old. ...

Therefore I do not plan to upgrade PHPClasses site server to Apache 2.x for now. In any case I would love to hear from people with a different experience.


Popular posts from this blog

111 Most Useful Websites on the Internet

How to call php functions inside smarty template directly

How to improve PHP web performance