Archive for the 'AJAX' Category

AJAX Hello World with HTML_AJAX

Wednesday, August 17th, 2005

This is a continuation of my AJAX Hello World series, in my earlier posts I covered sajax and JPSpan. In this article i’ll cover how to get a basic AJAX appliction up and running with HTML_AJAX. If you haven’t figured it out yet im one of the author’s of HTML_AJAX. The application in question is the same simple app as the other examples, it has an input box for adding random strings and an button to add a random one to a div.

When your using HTML_AJAX you have more choices then with either JPSpan or sajax. But to keeps things simple were going to use a setup similar to how we used JPSpan, an external server page that generates a JavaScript proxy which is included by our html page that does the actual action. HTML_AJAX could also be used sajax style with the proxy and server code generated inline, but I don’t recommend this usage since it remove your ability to cache the generated JavaScript.

Installing HTML_AJAX

This is nice and simple its simply:
pear install HTML_AJAX-alpha
If you don’t have pear setup on your server just follow the installation instructions in the PEAR Manual.

Setting up the Server Component

An HTML_AJAX server page is generally very simple, it creates an HTML_AJAX_Server instance, registers all the classes you want exported and handles incoming requests. The incoming requests can be three different types:

  • Client library request: query string includes ?client=all (can also be each of the seperate component parts)
  • Generated stub requests: query strings includes ?stub=classname (all keyword can also be used)
  • AJAX Requests: query string includes ?c=classname&m=methodname

Client and Stub requests can be combined into the same one, but remember there is a tradeoff when doing that. You’ll have less roundtrips to the server but generated stubs are more likely to change so they can hurt your cacheability. You also want to be careful about using stub=all since the stub for 10 different classes can be quite large. The next release will also allow for combining multiple classes in a stub request by seperating them with a comma like so: stub=test,test2. Finally a note on class names, in php4 they will be lower case since thats what PHP returns, if you would like to have case or need to guarantee php4/5 compatability you’ll want to use some optional paramaters to registerClass, the first is the name to register the class in JavaScript as, the second is an array of methods to export.
A basic server is shown below.

<?php

session_start();

require_once 'HTML/AJAX/Server.php';
require_once 'HelloWorld.class.php';

$server = new HTML_AJAX_Server();

$hello = new HelloWorld();
$server->registerClass($hello);

$server->handleRequest();

?>

A server like this works fine for small scale projects, but it might not be a good choice for something larger since you could be creating 20 class instances just to serve a request on one of them. Any custom setup also has to be done for each class. HTML_AJAX provides a way to manage this by extending the server class and adding an init method for each class. A server that does this for the same HelloWorld class is shown below.

<?php

session_start();

require_once 'HTML/AJAX/Server.php';

class AutoServer extends HTML_AJAX_Server {
        // this flag must be set for your init methods to be used
        var $initMethods = true;

        // init method for my hello world class
        function initHelloWorld() {
                require_once 'HelloWorld.class.php';
                $hello = new HelloWorld();
                $this->registerClass($hello);
        }

}

$server = new AutoServer();
$server->handleRequest();

?>

PHP Application Code

In the server examples above you’ll notice were including a Hello World class. This hasn’t changed from the JPSpan example. The only thing of note is that makes heavy use of session, many AJAX apps will share this same heavy use, so make sure your server setups can handle that.

<?php

// our hello world class
class HelloWorld {

        function HelloWorld() {
                if (!isset($_SESSION['strings'])) {
                        $_SESSION['strings'] = array('Hello','World','Hello World');
                }
        }

        function addString($string) {
                $_SESSION['strings'][] = $string;
                return $this->stringCount();
        }

        function randomString() {
                $index = rand(0,count($_SESSION['strings'])-1);
                return $_SESSION['strings'][$index];
        }

        function stringCount() {
                return count($_SESSION['strings']);
        }
}

?>

The HTML that ties it all together

To finish up our app we need to create the HTML that ties it all together. This is going to have two main parts, the main JavaScript logic, callback function for our async requests and a fake form. The call the form fake, because there is no form tags, were just powering everything off onclick event handlers on buttons. At some point in the future HTML_AJAX will support taking a normal form and magically turning it into an AJAX one but for now that thought is just in my head.

The page starts with normal HTML boiler plate and an include of our client library and the stub hello world class. They are done all in a single class since that makes sense for this example, if I had 10 classes it wouldn’t.

Next we build the callback hash, it has a method for each method in PHP, they will be called from the results from an async AJAX call. In this example each call back is really simple it either updates an element using innerHTML or appends to one. You could also use a normal JavaScript class instead of a hash, but thats only useful if you need multiple instances.

The next step is to create an instance of our helloworld class and create a helper function. When we create an instance of our proxy class we pass in our callback, if we didn’t the instance would work in a sync manner, which can be useful, but in this case would make for a choppy ui. The helper function do_addString isn’t anything exciting, it just clears out the textbox after we’ve submited its current value.

Finally we have the html body of the page, it contains our buttons with onclick event handlers that call remote functions. It also contains our output divs.

Trying out the sample

If you got this far you’ll want to try out the Hello World app were building. If you compare it against the JPSpan or sajax version you won’t notice many differences. The only visual one that should show up is loading notice in the top right corner. Since providing user feedback is such an important part of making a usable AJAX application HTML_AJAX includes this basic loading symbol out of the box. If you just want to customize its looks you just need to create an element with the id of HTML_AJAX_LOADING. Its shown by setting its display style to block, and hidden by setting display to none everything else is left up to you so make sure to take care of any positioning and setting its display to none so its hidden by default. If you want to do somthing more complex you can override HTML_AJAX.onOpen and HTML_AJAX.onLoad check out the current methods to see hows its done.

Finally you might notice some JavaScript errors if you try to make a lot of quick requests, like JPSpan HTML_AJAX only provides for one concurrent request at a time. This will change in the future giving you a number of different options but for now you can either keep those from happening at the application level, or just add a error handling function to HTML_AJAX.onError and ignore the call in progress ones.

You can also download the project and try it out on your own server, its available as a tar.gz or a zip.

Where to go from here

Now that you’ve had a look at HTML_AJAX you might be wondering how to learn more about it. For the moment your options are pretty limited. You can check out the examples dir (in the docs dir in pear or online) or you can ask questions on this post. You might also find the source to be useful, for now the newest version lives on my svn server.

Feed back is appreciated as I’ll use that to decide what features to add to HTML_AJAX and what to fully document next, feel free to post comments or trackbacks even if you have a lot to say.

Update:
This example won’t work correctly in PHP5 since the methods will be exported with CASE, take a look at the generated JavaScript if you don’t understand what i mean (auto_server.php?clalss=helloworld). See Comment #40 for your options to fix things.

Say Hello to HTML_AJAX

Thursday, August 11th, 2005

HTML_AJAX had its first PEAR release today. Its the same version as was voted on so there is no new code but you can use the PEAR installer to get it.

Once you have it installed you’ll find the examples in the docs dir to be quite helpful, on my server thats /usr/share/pear/docs/HTML_AJAX/examples. These examples are also available online: run, view code.

I’ve started a basic website for the project, it includes a development roadmap, so if you want to help out, or just want to know whats happening next thats a great place to start.

HTML_AJAX has two different main use cases, standalone and proxy.

Now in proxyless/standalone mode you can use just the JavaScript library making requests to pages and working with its results however you want.

To accomplish this basic usage you either need to create a instance of a server class that will server the JavaScript libraries, or copy them into your web root. These js files are located in your pear data directory, on my server thats: /usr/share/pear/data/HTML_AJAX/js.

Setting up a server that will handle client requests is easy, a basic one is shown below:

<?php

include 'HTML/AJAX/Server.php';

$server = new HTML_AJAX_Server();
$server->handleRequest();

?>

If you save that as server.php you can include the needed JavaScript libraries like below:

Once you have the libaries pulled in you easily make various AJAX calls, the main usage for proxyless operation is to pull down some new content and put it into your page using innerHTML. Any asyncronous example of this is shown below:

A sync version of grab is also available, just don’t pass it a callback function. This is even easier to use but has the disadvantage of blocking while the download happens. In some circumstances this can useful since your already in a callback, but you have to be careful when using it. Besides the grab method there is also a replace method it takes an id and replaces its innerHTML with the results. Finishing up the standalone api there is a call method which allows you to call methods on classes registered with the server. Registering classes is shown in the proxy section. A sample async call is shown below:

Call can also be used to do sync calls just pass false in instead of a callback function.

Moving on from the basic standalone api HTML_AJAX offers generated proxy classes. You start this usage by registering a class with the server. The class will be introspected and public methods will be exported (methods starting with _ are considered private).

<?php

include 'HTML/AJAX/Server.php';

class test {
  function rot13($string) {
    return str_rot13($string);
  }
}
$test = new test();

$server = new HTML_AJAX_Server();
$server->registerClass($test);
$server->handleRequest();

?>

After that you need to include the generated proxy class. After that you can create an instance of that, when you do it you pass in a callback class. An example of this calling the rot13 method is shown below.

There is some other optional functionality around as well, the examples show documentation of pretty much everything. I’ll write more formal documentation as I have time. If you have any questions feel free to ask them on this post, and i’ll either reply in the comments or in a new post if there is enough of them.

Cake, mp3act and lots of other AJAX Updates

Tuesday, August 9th, 2005

I’ve been slowly updating my AJAX resource list, I’m down to about 20 items on my incoming list now to review. The biggest things i’ve found recently are the Cake PHP framework, and mp3act.

Cake is a PHP framework based on Rails, I like frameworks of that style because they don’t need any configuration files, its 100% code driven. Cake seems to have a focus on making things easy for the User, and its AJAX support is no exception, the helpers class looks like it really cuts down on the amount of code needed to get things done. There is a neat example page that was created to shown off all the AJAX stuff that cake can do. If you goto the website an notice its quite parse, take a look at the trac site, it has some pretty good docs linked off the menu bar on the right side, the site was moved recently and it seems that a website redesign is lagging behind.

mp3act is a one of those streaming music servers, its based on PHP and sajax (which wouldn’t be my choice but I guess its been around for awhile). It really shows what you can accomplish if you don’t worry about browser compatability and just code for firefox. That being said, I don’t see anything there doing that couldn’t be done on IE is well. Which brings me to an interesting point that I read in the Alex’s OSCON slides, you don’t want to be writing JavaScript yourself. I mean feature-wise JavaScript isn’t a bad language, it has prototype based OO and dynamic closures, and a decent programming environment in Firefox, but there is still IE to worry about (and Opera, and Safari). Each browser has a bug here, or something not completely implemented. Working around these bugs isn’t something you want to do on your own, by using Open Source libraries we can share in the work and the fixes. With a little bit of luck will all be able to create powerful AJAX apps without having to go the mp3act route.

I’m going to keep this pattern up of only posting update overviews on a weekly or bi-weekly basic since I don’t like clogging up my blog with tons of little update posts. If you want to see whats happening on a daily basic I’ve added a recent updates page. I’d like to add an rss or atom feed for that as well as the rest of the resource pages, but I don’t want to bother with learning any of the standards. If anyone knows of a feed writing class that works in PHP4 let me know.

Also I’ve thought about injecting the updates into my regular feed (not the one that goes to planet-php), but im not sure how reasonable that is to do in Wordpress or how kosher it is to inject almost blog content into my blog feed. Any thoughts on this would especially be appreciated.

Libraries

Behaviour : Using CSS selectors to apply Javascript behaviours
Small JavaScript class that can be used to apply behaviours to documents in a non intrusive way
CakePHP
Rails port to PHP, provides the same type of AJAX tie-ins

Articles

Will AJAX help Google clean up? | CNET News.com
General AJAX coverage focusing on Big players like Google, MS, Macromedia/Adobe and how AJAX will affect the market for things like Flash and XAML
Christian Cantrell: Deep Linking in Flash and AJAX Applications
Article which discusses problems with linking to a page created using AJAX, different techniques and there problems are covered
PXL8 - IFrame Remote Scripting
Article covering howto load data from a remote server using IFrames
Using the XML HTTP Request object
Article covering the ins and outs of using XMLHttpRequest on various browsers, various requests such as GET POST HEAD are covered

OSS Applications

mp3act - Streaming MP3 Jukebox AJAX Web Application
A PHP GPL application that provides a Streaming MP3 Jukebox, only Firefox and Safari are support.
Broken Notebook AJAX spell checker
A php project that adds spell checking to a textarea using the pspel/aspell extension and cpaint

Blogs

AjaxDeveloper.org
AJAX blog aggregator, each posting contains a short quote and some commentary

Examples

Cake Framework AJAX Demo
Demo of all AJAX Helpers in Cake PHP Framework

Presentations

Building Dynamic Web Applications with AJAX
Slides to presentation given at the AzPHP Users group in April ‘05, gives an AJAX intro and shows a demo app built with JPSpan
Learning AJAX OSCON ‘05 Tutorial Session
Good overview of AJAX and then building an Auto-save text area with Dojo and Prototype, sample code linked from slides

Tag Filters (Update on Query Problems)

Tuesday, July 26th, 2005

From the couple responses I got to my posting about Query Problems it looks like there is no great solution to tag filtering. It does look like using a subquery for each tag you want to filter by works reasonable well up to at least hundreds of thousands of tags, so that approach should work just fine for me.

The actual filtering is in my AJAX resources, and is currently just on there attributes (language they are written in, etc) not resources other tags. I think to really make the filtering work nice i’ll use some sort of multi link approach were you can add the filter as an or link, as an and, or view view that tag. I’ve also been thinking about adding some AJAX to the page just to show it off, but I’m not sure its really helpful to usability besides possible faster loads times, I’ll have to think about it a little more.

An example of why the filtering was added is now you can see all the PHP AJAX libraries, where before all the Ruby or Perl ones would be mixed in.

HTML_AJAX

Friday, July 15th, 2005

If your on the pear-dev mailing list you should have already seen the post but i’ll blog about it here as well hoping to get some feedback.

A proposal was made on pepr for an HTML_AJAX library in PEAR. I was less then happy with the implementation and since once a package is in PEAR its hard to replace I thought i’d step up and provide a package that I think is ready for widespread use. I wasn’t really considering doing this before this came up, since its a lot of work, and JPSpan has been working fine for me (thats not to say I wouldn’t do some things differently). So here is an alpha release of my HTML_AJAX library.

Anyhow im actively looking for someone to come aboard as a co-maintainer of this package, if your interested let me know.

Its goal is to over OO javascript proxy and proxyless operation. Sync and Async AJAX calls, with an optional JS library offering things like a content replacement api. It should be usable in a server style setup (JPSpan) or directly in a page (Sajax). Its curently doing all communication using JSON, but that might change if someone sees a good reason.

The current feature set is:

  • Ability to register multiple classes on one page
  • JSON is used for communication in both directions (I made add JPSpan xml from JavaScript to server as well)
  • Class are exposed to Javascript as classes
  • POST is used for sending requests
  • Decent JavaScript error handling (right now there is an alert catch on the errors, but we might just leave the exceptions alone at some point)

Next Steps are:
In the Javascript code:

  • Decide if JavaScript JSON implementation has a license that is ok (json.js)
  • At least switch to a smushed json.js (3k instead of 10k)
  • Clean up HTML_AJAX.js, I pull in a bunch of classes from JPSpan and I think they can be made smaller through refactoring
  • Expose onLoad etc events
  • Complete Async Callback support
  • Create an addon api that allows for, proxyless operation, direct content replacement from results

In the PHP Code:

  • Pearify JSON.php (this currently has a pepr proposal in the draft state, the author said he will try to move it forward, but who knows if he will have time)
  • Complete the api so it that is supports inpage operation like test.php, or out of pager operation (including the javascript proxy files)
  • Write code to deliver the js files through php with the proper caching headers, so you don’t have to copy the js files around unless you want too
  • Write a cache for javascript proxy files (I did this for JPSpan today so it should be too hard)

Improving JPSpan page load performance

Friday, July 15th, 2005

If you use JPSpan to augment a normal website you may have noticed that your page loads now take quite a bit longer. The reason for this is loading the JPSpan client javascript code, its generated on each load and so it can’t be cached on the client. This file can become huge if you register lots of classes with lots of methods to create stubs for.

So the solution is to allow this page to be cached, to allow for that, im using HTTP_Cache, i’ll also be caching the output generated by PHP since the client files shouldn’t change often.

When you start caching the most important question to answer is, “How do I know when I need to regenerate my cache”. In the JPSpan case two things can cause a cache regen, the server url changing (the url of the JPSpan server is embedded in the file) or the api your exporting changing. The server url changing might not ever happen for some people, but in my usage the ip is different depending on if your using the VPN or the public url so this needs to be taken into account. Its also good to take into account so that a stale cache file from development doesn’t ruin things.
Now the api is a little harder, but since JPSpan has to know what to export, its something that must be available.

In fact its in the descriptions array on the JPSpan_Server_PostOffice Object. So to know if its change you just make a hash of it, and check for a change in that. Code to make our API hash is shown below.

<?php

// create a hash from the api of the handlers
    // turn the descriptions into a string
    $api = "";
    foreach($S->descriptions as $key => $val)
        $api .= $key;
        foreach($val->methods as $method) {
            $api .= $method;
        }
    }
    $apihash = md5($api);

?>

Now that we have the information we need on when to regenerate our cache its just a matter of implementing it. First will implement the client side cache, to do this we Use HTTP_Cache to send 304 codes when nothing is changed. The code to do this is shown below, notice that were not compressing the generated JavaScript yet (strip whitespace comments) since its a really expensive operation, that will have to wait until we cache that part too. Also take not that were not calling displayClient anymore, its echo’s it output and then calls exit, so that makes its pretty useless for caching.

<?php

        // setup HTTP_Cache give it our custom etag and see if we need to generate the client
    require_once 'HTTP/Cache.php';

    $cache = &new HTTP_Cache();
    $cache->setEtag($etag);

    if (!$cache->isValid()) {

        // Compress the output Javascript (e.g. strip whitespace)
        //define('JPSPAN_INCLUDE_COMPRESS',TRUE);

        // Display the Javascript client
        $G = & $S->getGenerator();
        require_once JPSPAN . 'Include.php';
        $I = & JPSpan_Include::instance();

        // HACK - this needs to change
        $I->loadString(__FILE__,$G->getClient());
        $client = $I->getCode();
        header('Content-Type: application/x-javascript');

        $cache->setBody($client);
    }
    else {
        // something is setting Cache-Control
        header('Cache-Control: must-revalidate');
    }

    $cache->send();

?>

Now if things are working correctly the web browser shouldn’t be fetching the entire page after the first time, it should just be getting a 304 header as the result. There are a couple ways to test that this is working, the easiest it too just view the client page, get the page info in firefox and see if its in your browsers cache, if not then something is broken. In debugging these types of problems i’ve found the LiveHTTPHeaders firefox extension to be useful. What your looking for is the server to send the ETag and then the client to respond with it on the next reload. The server should then respond with a 304 instead of a 200.

Now the next step in the process is to add a file cache in php for the generated client stubs so that we can turn on whitespace stripping and make the first download faster. Thats pretty simple stuff, just make your filename, check if the file exists, if so use it, otherwise generate the client as write it out to file for latter use. I’m using file_put_contents to write to the file so if your on php4 you’ll want to replace that code or check out PHP_Compat. Complete code showing both client side caching using HTTP_Cache and 304, and server side caching is shown below.

<?php

// Include JPSpan and setup your server here
// now our new updated client serving code with lots o caching
if (isset($_SERVER['QUERY_STRING']) && strcasecmp($_SERVER['QUERY_STRING'], 'client')==0) {
    // cache dir
    $cacheDir = APP_ROOT."/tmp/";

    // create a hash from the api of the handlers
    // turn the descriptions into a string
    $api = "";
    foreach($S->descriptions as $key => $val) {
        $api .= $key;
        foreach($val->methods as $method) {
            $api .= $method;
        }
    }
    $apihash = md5($api);

    // get the host the request is being made with since it gets embedded in the client file
    $server = preg_replace('/[^a-zA-Z0-9._]/','',$_SERVER['HTTP_HOST']);

    // create the filename
    $cacheFile = "client-$apihash-$server.js";

    // create the etag
    $etag = md5($cacheFile);

    // setup HTTP_Cache give it our custom etag and see if we need to generate the client
    require_once 'HTTP/Cache.php';

    $cache = &new HTTP_Cache();
    $cache->setEtag($etag);

    if (!$cache->isValid()) {

        if (!file_exists($cacheDir.$cacheFile)) {
            // Compress the output Javascript (e.g. strip whitespace)
            define('JPSPAN_INCLUDE_COMPRESS',TRUE);

            // Display the Javascript client
            $G = & $S->getGenerator();
            require_once JPSPAN . 'Include.php';
            $I = & JPSpan_Include::instance();

            // HACK - this needs to change
            $I->loadString(__FILE__,$G->getClient());
            $client = $I->getCode();

            file_put_contents($cacheDir.$cacheFile,$client);
        }
        else {
            $client = file_get_contents($cacheDir.$cacheFile);
        }

        header('Content-Type: application/x-javascript');

        $cache->setBody($client);
    }
    else {
        // something is setting Cache-Control
        header('Cache-Control: must-revalidate');
    }

    $cache->send();

} else {

        // This is where the real serving happens...
        // Include error handler
        // PHP errors, warnings and notices serialized to JS
        require_once JPSPAN . 'ErrorHandler.php';

        // Start serving requests...
        $S->serve();

}

?>

Update: added data cleaning around HTTP_HOST since I use that in a file name

AJAX Resources layout changes and tag fun

Thursday, June 9th, 2005

So now that I have a working internal bookmark system that passes it data through to del.icio.us i’ve finished the next step and converted the resource pages on my blog to using my custom rendering pages. Its much simpler then parsing rss feeds since I actually have the database so I just wrapped my 3 table solution in a couple objects.

Unfortunatly this moved the urls since the new pages need to match up to tag names. At some point i’ll have a solution for this, but the mod_rewrite rule is already getting a bit scary.

The front page stayed the same but the subcategory pages changed:

You’ll notice less high level subcategories on the library front, some will come back as I get my tag set figured out and coherent, but since each entry shows the tags you have more information anyway.

Changes to the list can be found on my del.icio.us feed, but thats not quite as useful since my long descriptions aren’t stored there. You’ll also notice how im abusing tagging a bit, there are tons of tags named category:value, I call these attributes and will hopefully allow me to easily create lots of different view of this data.

If anyone wants to take a look at the code let me know, I’m not sure if I want to go open source with it since its really hackish right now, but if someone wants to help make it more generic (less of my urls hardcoded in it) send me an email.

Oh and if anyone is wondering how im manging the wordpress integration the trick is page templates.

And finally my todo list on this project:

  • Add editing support
  • Create my own feeds so all the info is available
  • Provide generic tag browsing by making them links everywhere and adding a generic mod_rewrite rule for them
  • fixing my mod_rewrite rule to make the old urls work?

Lots of AJAX Resource updates

Tuesday, June 7th, 2005

Thanks to everyone who posted links on my last post, besides a couple articles it wasn’t anything I hadn’t seen before but it was push to get those things added which is great.

New Updates:

Articles

  • XML.com: Very Dynamic Web Interfaces
  • ONLamp.com: A Simpler Ajax Path

Blogs

  • Ajax Blog

DHTML Libraries

  • dojo: the browser toolkit (note this has a AJAX lib in it as well)

JS AJAX Libraries

  • Prototype: Object-Orient Javascript Library (note this has a dhtml effect library too)

Toolkits

  • Toxic

Reviewing this new round of content I noticed a couple things, there are lots of same old intro to XMLHttpRequest posts, and most libraries and toolkits have poor documentation even if they have lots of it.

The most important thing for any project open source or not is to getting started guide that gets a user acomplishing your projects main purpose with as little effort as possible (Yeah I know phpDocumentor is missing this too).

On to different point, the basic CMS in wordpress sucks for managing this, anyone have any suggestions my needs are.
Easy to create and use simple templates for each item
The ability to tag items so they can be in multiple categories
The ability to view items in category lists like they are now

If anyone has any suggestions on some opensource project that I can integrate easily with wordpress (shouldn’t be hard its cms is mod_rewrite based) let me know. I wouldn’t even mind hacking up some code but I really don’t need a new large project, cause plain old brute force text editing always works even if its painful.

Also on a totally unrelated note, wordpress timezone management sucks. Times should still be UTC on the darn rss feed even if they are MST when view on the blog, or at least they should be reported as MST and not UTC with 7 hours subtracted, now to hack in a solution.

AJAX Resources

Monday, June 6th, 2005

I’ve started compiling lists of the various AJAX resources i’ve found. This is mainly to help me out in some of the writing i’ve been doing but I thought it would help all of you out as well.

Some people do this sort of thing with tons of blog posts, but I’m not really happy with the sort of organization system you get for that sort of thing. I’m using the wordpress pages functionality to manage my lists, its just basic cms functionality if i see that this doesn’t work, i’ll have to parse the html and put all the content in a db, but for now this is easier.

The content is pretty basic right now since I try to write a small overview for everything on the list and It takes me time to refind things I read but forgot to bookmark.

If you know of anything that fits into one of the categories let me know on a comment to this post thanks.

php|arch AJAX Presentation wrapup

Thursday, May 26th, 2005

My slide post about the presentation is actualy backdated to the 23, I forgot to future date it when I started things and now things are using the link. But anyhow there is no magic the webcast was today and it went well.

I couple questions I want to answer in more detail are:

What are some PHP AJAX toolits?

  • JPSpan - OO Api Sync and ASync mode
  • SAJAX - Procedural Api ASync Only? multi-language support
  • JSRS - Async only, uses IFrames, multi-language suspport
  • SRSS Sync Only, Content Focused

If anyone knows of any other AJAX toolkits for PHP let me know, there are also lots of JS toolkits that don’t handle data serialization but could be used to grab content from a php server.

What browsers does JPSpan support?

There is a list on the wiki.

Why don’t you just use SOAP?

I think its overkill and doesn’t take advantage of the fact that both PHP and Javascript are dynamically typed. Again more details on the wiki (also why not XML-RPC, WDDX etc)

What are some example PHP apps using AJAX?

I’m going to need some help to answer this one, I know there are lots of projects that have stuff implemented in CVS but I don’t know of much that is released.

A couple of Uversa’s apps use it: SureInvoice (type ahead search when inputing time) and Clearhealth (typeahead find of patients, report attachment screen in admin, and fee schedule editing)

What are the security considerations?

Well beides normal XSS implications im not to sure. As far as I know if you make sure to escape any user data as needed you should be ok, since the normal browser security model should take care of the rest. Please leave a post if you’ve found any news about this.

Where are the slides, and will this session be available latter?

The slides are here on my blog, php|arch will have a recording of the session up soon.

There were a number of other questions which I don’t remember anymore, but i’ll be sure to answer any other questions about AJAX that people have.

Also my employer is looking to hire some developers so if your interested in working with open source PHP doing some exciting stuff (lots of AJAX) make sure to send in a resume, were only accepting them until the 30th.

Building Dynamic Web Applications with AJAX webcast Presentation

Monday, May 23rd, 2005

If your coming here from the php|arch webcast, welcome, and from anywhere else too.

It looks like the presentation server had some sort of outage, during the question and answer period, we recovered quicly and though we lost about a hundred people, I think most people got there questions answered.

If you have an more questions feel free to post them here.

The slides are available online, these are slightly different then the version in the presentation, but the content is the same, they’ve just had a little less editing.

The example application is also online
.

AJAX File upload Progress

Sunday, May 1st, 2005

Example of how to use the newest version is available in another post.
Update
There is a new version of this code that follows the same approach but uses HTML_AJAX instead of JPspan.
You can view the new demo, and view the code in websvn.

Also note that the server isn’t setup to accept files larger then 8meg, so anything bigger will fail.

Also I’m looking for someone to help me improve the error handling, if your interested in getting involved and making some regular releases of the new code let me know.

Original Post below

A couple days ago I found an interesting ruby on rails project. It uses AJAX to update a progress bar as the file uploads. The trick is a patch to rails for getting upload status and doing the upload in an iframe so that the main page is still active.

So to replicate this I just had to find a patch that provides upload status in PHP and then implment my little iframe upload widget.

I found the PHP with a little work from google: Upload Progress Meter

First you need to install the patch and the extension, the included instructions are easy to follow. The only problem I found is that: upload_progress_meter.store_method = “file” had to be set in my php.ini before thing would work.

I also ran into a JPSpan problem, if your having network problems the status call might take longer then 1 second, and you’ll get Call in Progres error alert. This can be fixed with the current version of JPSpan but i’d like to see some api added to help. The proxied objects need some type of inProgress call to make this an easy fix.

One item of note is that the extension only provides information in a way to provide 1 progress bar per form no matter how many files. The javascript code is setup so multiple forms could be on a page at once and both uploading, but this hasn’t been tested.

Here is the demo you’ve been waiting for, for most connections a 250k file will be enough to see something besides connecting and complete.

Also if anyone has the time and skills to review the php patch and see what it would take to get integrated, please let me know. I haven’t heard from its author so I don’t know why its not integrated but it just seems crazy to have a 3K patch that is this useful only available to those who are willing to patch.

Code walk through

So the basic flow happens like this.

Display a page with a form:
this page has a hidden iframe, a hidden progress div, and some extra javascript code

Select the file to upload and submit the form:
The form has a target of the hidden iframe so even though the throbber starts the main page view won’t be getting new content when the upload is done.

The form onclick handler fires a setup function:
The function finds the progress div and shows it, it also registers a function to update the status ever second.

The update function fires every second:
This functions checks a counter to see if there are any more divs to update, if the counter is 0 it stops the update function from firing again
The function creates a remote proxy object to the php class UploadProgressMeterStatus if it hasn’t already been created
The function calls the get_status method on the proxy object with a list of all the progress divs and UPLOAD_IDENTIFIER’s that we need status for.
The function exits

The get_status method on the php class is called
The method calls upload_progress_meter_get_info() for each passed in identifier, the information is formated to a percent and a message which is returned

The callback function for get_status is called when the PHP class returns data
The callback updates the progress div
If were at 100% the we decrement our progress div counter and remove us from the list of divs to be updated

The iframe can also load a page once the file upload is done, it doesn’t currently do anything.

Example Code

This is really the only interestin php code in the project, and its not that interesting. When you have the Upload Progress Meter extension installedany form that is doing a file upload and has a hidden var called UPLOAD_IDENTIFIER can be tracked. The identifier has to be passed into the upload_progress_meter_get_info function so you have to keep track of it on the javascript side. Here we just pass those ids in, do a bunch of formating on the resulting array, and return the results. Note the returned array isn’t documented anywhere so this code and the code in the example php code provided with the extension is the best place to start if you want to do something else with it.

<?php

       /**
         * Get the status of all uploads passed in
         */
        function get_status($ids) {
                $ret = array();
                foreach($ids as $id => $upId) {
                        $ret[$id] =  new stdClass();

                        $tmp = upload_progress_meter_get_info($upId);
                        if (!is_array($tmp)) {
                                $ret[$id]->message = "Complete";
                                $ret[$id]->percent = "100";
                                break;
                        }

                        if ($tmp['bytes_total'] < 1) {
                                $percent = 100;
                        }
                        else {
                                $percent = round($tmp['bytes_uploaded'] / $tmp['bytes_total'] * 100, 2);
                        }

                        if ($percent == 100) {
                                $ret[$id]->message = "Complete";
                        }

                        $eta            = sprintf("%02d:%02d", $tmp['est_sec'] / 60, $tmp['est_sec'] % 60 );
                        $speed          = $this->_formatBytes($tmp['speed_average']);
                        $current        = $this->_formatBytes($tmp['bytes_uploaded']);
                        $total          = $this->_formatBytes($tmp['bytes_total']);

                        $ret[$id]->message = "$eta left (at $speed/sec) $current/$total($percent%)";
                        $ret[$id]->percent = $percent;
                }
                return $ret;
        }

?>

On the javascript side there is a bit more code, but none of its all that complex. This code is used to show the progress bar and give it some initial values. The main things to notice are that were add an update method to the div, this is a nice trick since it allows for runtime extension of objects in the DOM, and it will make updating things nice and easy in the other functions. Were also adding a getFirstDivByClass method to the div, I’m doing this so I don’t have to have so many divs to track, the classes only have to be unique inside the progress bar for this to work and thats much easier to achieve.

The code below calls the remote proxy and creates the callback function to handle the results. The is one area where improvements could be made. First there should be a check if there is currently a call in progress. Then it might also be smart to call the server less (especially on large files) and just generate the stats from the current download rate. This would add some complexity but would allow the progress bar to update smoothly and would allow the server calls to get down to once every 5 or 10 seconds.

If you don’t do a lot of javscript programming its worth nothing the use of for(var prop in result) and delete UploadProgressMeter_active[prop];

for(var prop in result) is how you loop through the properties on an object, this allow you to use them as associative arrays (just watch for methods on the objects since you’ll loop through them too).

delete UploadProgressMeter_active[prop] is the equivalent of unset($array['key']);


Code List

Updates

You may have noticed that the demo has stopped working a couple times. This was related to 2 things and there things you might want t think about if your going to use the patch. First it writes tmp files and fails silently if the directly no longer exists (darn /tmp cleaning scripts). Second its on my php5 server which has some users who are pushing the envelope which required me to upgrade to the php 5.1 beta and I forgot to repatch. Repatching wasn’t a big deal though I did have to move where a function was declared to get the extension to compile in gcc 4 (I upgraded to fedora core 4 as well).

Anyhow the demo is working and it should stay working as long as I remember to repatch with each upgrade.

New Version

This code has been updated to work with HTML_AJAX and to handle error conditions better. I haven’t done a formal release but you can grab it from svn.

Check it out from: http://svn.bluga.net/HTML_AJAX/UploadProgressMeter/trunk/

Or use websvn to get a tarball: http://websvn.bluga.net/wsvn/HTML_AJAX/UploadProgressMeter/trunk/?rev=0&sc=0

Also if your interested in helping out with the Upload Progress Meter let me know

AJAX webcast presentation on May 26th

Wednesday, April 27th, 2005

I’ll be presenting an updated version of the presentation I gave last night at AzPHP as a free webcast for php|architect on May 26th. The major change will be a new technical introduction centered around getting you started with JPSpan and building a simple widget.

The live talk will begin at 1:00 PM EST (10 AM PST, 6PM GMT), space is limited so if your interested you’ll want to sign up today.

AzPHP AJAX Slides

Tuesday, April 26th, 2005

The presentation went pretty good tonight, the turnout was pretty good, lots of new faces.

I kept dropping the wireless connection which didn’t help with showing sample apps, but we recovered pretty well. Anyhow the slides are up take a look, any feedback would be appreciated since i’ll be giving an updated version in another month or so.

Slides for AzPHP Presentation: Building Dynamic Web Applications with AJAX

Improving JPSpan Performance with an Object Pool

Friday, April 22nd, 2005

Some people commented in my AJAX Hello World with JPSpan article that the JPSpan example app was quite a bit slower. After a bit of testing it does seem that the performance problems comes from each JPSpan object having only 1 XMLHttpRequest object, this means if you use 1 object you can only have 1 outstanding call.

I would like to see this fixed with an pool of XMLHttpRequest objects at the JPSpan level, however im sure this will take some time so I have a solution for you today.

Its a small javascript class that implements a simple autogrowing object pool for the create JPSpan remoting objects. I’ve created an updated version of the JPSpan Hello World app that uses the pool and it seems much faster to me.

To use the pool you just need to include objectPool.js.

Then you just need to setup your pool. You’ll notice that the callback object recieves a reference to its parent remote object, this will be used to return the remote object back to the pool.

When you make a remote call now just get the get the object from the pool first.

Then in the callback when your in the callback method you return the object to the pool. Note that you just pass back a poolId that is set on the object not the entire Object.

Thats it your JPSpan apps are now a lot more responsive (of course this means your hitting the server a lot more).

Full source of updated JPSpan HelloWorld app, Try updated JPSpan HelloWorld app, try old JPSpan HelloWorld app.

Couple notes on the Object Pool.

Its pretty simplistic right now there are a couple things im going to update.

  1. Allow returnObject to take an object back just to make things more fool proof
  2. Add in the ability to limit the pool size and various options if that happens, either performing a function on current objects to recover them or just sleeping for a bit
  3. Adding some maintenance methods to let you get specific objects from the pool

Im also going to investigate a couple things but im not sure if its worth it.

  1. Allowing a pool to contain more then 1 type of object
  2. Adding in a method that checks if the object is ready to be returned to the pool instead of returning them with returnObject

If you think you’ll use this code or have any feedback on the items above let me know.

Great Javascript Library

Wednesday, April 20th, 2005

I’ve been working on a small AJAX image gallery application to use as a demo for my AZphp presentation next tuesday. I got to the point where i wanted to be able to drag some Images around, and while I could write the javascript to do this, I always try google first for a problem like this. Much to my surprise I found nice lgpl library that does everything I need.

It handles draging and droping of element, resizing them, cloning items, and some animation. I just started to scratch the surface but the code looks very well done.

If you know of any other javascript libraries please let me know, with a comment or trackback.

AJAX Hello World with JPSpan

Tuesday, April 19th, 2005

In my AJAX introduction post I talked about SAJAX and JPspan this posts walks you through installing JPSpan and writing the same simple Hello World app as we did in the SAJAX post.

Setting up JPSpan

  1. Download JPSpan: http://prdownloads.sourceforge.net/jpspan/
  2. Extract and copy the extracted folder to somewhere in your include path
  3. Your good to go

Create the JPSpan server component

JPSpan provides a lot more functionality then SAJAX, the biggest difference you notice on the javascript side of thing is that you have mapped objects, on the php side the biggest difference is that you have a server page and a client page.

The default JPSpan server is called JPSpan_Server_PostOffice, it can be used to map entire classes to javascript, or you can pick and choose. If you were using the server on a large site you might want to add a get flag called class to limit which classes get included and registered to limit the overhead, but I haven’t had any performance problems just letting 4 or 5 integration specific classes be registered all the time.

Note: the JPSpan examples set a constant called JPSPAN_INCLUDE_COMPRESS, that strips javascript whitespace, the code that does this performs horribly, so make sure not to turn it on

<?php

// Hello World class goes here will show that next

// Including this sets up the JPSPAN constant
require_once 'JPSpan/JPSpan.php';

// Load the PostOffice server
require_once JPSPAN . 'Server/PostOffice.php';

// Create the PostOffice server
$S = & new JPSpan_Server_PostOffice();

// Register your class with it...
$S->addHandler(new HelloWorld());

// This allows the JavaScript to be seen by
// just adding ?client to the end of the
// server's URL

if (isset($_SERVER['QUERY_STRING']) &&
        strcasecmp($_SERVER['QUERY_STRING'], 'client')==0) {

    // Compress the output Javascript (e.g. strip whitespace)
    // turn this off it has performance problems
    define('JPSPAN_INCLUDE_COMPRESS',false);

    // Display the Javascript client
    $S->displayClient();

} else {

    // This is where the real serving happens...
    // Include error handler
    // PHP errors, warnings and notices serialized to JS
    require_once JPSPAN . 'ErrorHandler.php';

    // Start serving requests...
    $S->serve();

}

?>

App code

The app code is really quite simple, just like in the SAJAX case, here I just copied and pasted it into a class and put the session setup code in the constructor. You can do anything you would with a normal class here, but remember, this class is being recreated for each call from the javascript side, so if you want to keep class members between calls you’ll need to put the class instance in the session.

HTML code to display it

There is greater seperation between html and php when using jpspan, you include auto generated tieing code, this should allow for easier client side caching with a little header work, which is useful if your just using the code to add an autocomplete widget to a current site.

JPSpan can be used asynchronously (using callbacks) or synchronously (directly returning), generally you want to use things asynchronously since sync calls can cause the ui to freeze while your waiting for feedback. Sometimes this is actually what you want, but you’ll want to post some sort of please wait message if your transfering much of anything. More detail are given in a JPSpan tutorial on the projects wiki. In this example were using all async calls to match the SAJAX HelloWorld app.

If you were paying attention to the app code you might have noticed one minor difference between this JPSpan version and the SAJAX version. Addstring returns the count in this version, SAJAX automatically handles multiple async calls at once JPSpan doesn’t seem to so all that extra remote call gives JPSpan a problem.

This project is the first time i’ve used SAJAX and I think its ability to handle multiple outstanding calls is a big benifit. There is nothing to stop JPSpan from adding this ability but it has had a release lately so im guessing it will need someone to step up to the plate and write some actual code to get it done.


View Hello world app
, server.php source, index.php source

In my next post i’ll investigate how well SAJAX and JPSpan handle passing complex data types.

AJAX Hello World with Sajax

Tuesday, April 19th, 2005

So in my last AJAX post I talked about a couple AJAX toolkits for PHP. Today I’ll cover a small example using SAJAX.

Setting up SAJAX

  1. Download SAJAX: http://www.modernmethod.com/sajax/download.phtml
  2. Copy Sajax.php from sajax-0.10/php to somewhere in your include path
  3. Your good to go.

Hello World php code

Now using AJAX for hello world is a bit over kill but we need an example so in this example will display a random string generated on the php side.

App php code

Just some simple functions to add strings to a session array, return its count, and to return a random string from it.

<?php

        session_start();

        if (!isset($_SESSION['strings'])) {
                $_SESSION['strings'] = array('Hello','World','Hello World');
        }

        function addString($string) {
                $_SESSION['strings'][] = $string;
                return true;
        }

        function randomString() {
                $index = rand(0,count($_SESSION['strings'])-1);
                return $_SESSION['strings'][$index];
        }

        function stringCount() {
                return count($_SESSION['strings']);
        }

?>

SAJAX setup

Include Sajax.php and register functions that we want exported to javascript.

<?php

       require("Sajax.php");

        sajax_init();
        //$sajax_debug_mode = 1;
        sajax_export("addString");
        sajax_export("randomString");
        sajax_export("stringCount");

        sajax_handle_client_request();

?>

HTML Code

The important thing to note is that SAJAX uses callback functions for return values so for most calls you’ll need 2 javascript functions. Otherwise its just simple DOM interaction in this example.

View code of the entire script, view hello world example.

Building Rich Web Applications with AJAX

Tuesday, April 12th, 2005

So a couple months ago Jesse James Garrett gave us the worst new technology term ever, AJAX. Now I think a much better term is javascript remoting, or just javascript remote procedure calls using xmlhttpclient. But AJAX now seems to be the word of choice so were stuck with yet another meaningless acronym just like SOAP.

Now onto the actual topic, how you use the new technology with PHP and what it means to your average PHP developer. The first thing you want to do is just like another other new tech in PHP, ignore the original article and generic explanations and find a library that does the hard work for you.

Right now your options seems to be:

  1. SAJAX which offers a simple procedural api on both the javascript and php sides of the equation, It also provides support for other server side languages.
  2. JPSPAN which maps php objects to the javascript world.

Using either approach you have easy access to moving data back and forth between the php and javascript worlds, so at this point all the new tech been done for you, now you just need to use it which is the hard part. So the biggest change is you’ll be writing a whole lot more javascript, most of it interacting with the DOM. While many of use have avoided it like the plague its not all that bad if you only worry about supporting Firefox and IE 6.0, and its a pretty nice experience if you only have to support Firefox.

If you don’t enjoying playing with the DOM then the AJAX revolution will take a bit longer to get to you, but don’t worry it shouldn’t long before people start releasing widgets for doing that side as well. I expect that you’ll see type-ahead find, multi-select pulldowns, and database grids.

What this means to the average php developer is that you’ll have the abilility to reduce page reloads and make your webapp feel a lot more like a normal desktop app. At the moment you still have to do the work yourself, but im guessing you’ll see turnkey widget solutions in the next couple months. As I get time i’ll attempt to post a couple tutorials and if I ever stop spending time fixing up my apartment i’ll release the type-ahead find code we’ve built for clearhealth.

Life and Really Cool Code

Friday, March 4th, 2005

In November I came back early from my time in London to join a small Open Source php company here in Phoenix. I wasn’t sure if I was going to stay in Phoenix long term but its managed to work out that way, last week a sign a lease for an apartment at Indigo Palms.

Anyhow, work has been extremly busy making it hard to do anything at all on phpDocumentor of PHPca, but there is a bright side to that. Were an open source company and were slowly releasing our projects out as open source. The big thing im hoping to get out soon is our Celini application base, so I can talk about some of the cool stuff were doing with JPSpan.

On that note I have a small proof of concept demo of what can be done with direct javascript rpc to your php code.

The context is an editor for fee schedules in a medical clinic, there are something like 18K codes in the full table, I only have 1K loaded in the demo. You can scroll up and down (just links any information on using scroll bars in js for this would be appreciated) with information being loaded as needed. You can also click on the fields with a border to edit them, click on another cell saves the first one.

There is still a bit of work to do, mainly in filtering, jumping to any row, better edit interaction (enter saves, keys bound for up, down), and maybe a scroll bar.

Anyhow I thought I’d let the world have a small peak at what im doing these days, and hopefully i’ll have time to get the source ready to share in a week or too.

View the demo (NOTE, this code will eventually be released as GPL).

This circle expands additional navigation
You should really buy my AJAX book.
You'll learn not only the technology you need for implementation but also an understanding that will help you get the most from AJAX.
You'll also have my eternal thanks :-)