JAXL BOSH Demo: IM chat client for all WordPress blogs

Have you ever wished of a wordpress plugin capable of providing a facebook style chat bar on your blog post. In this blog post, I will lay down the details of how Jaxl‘s bosh support comes in handy for building such browser based real time application. Specifically, I will explain how I achieved building a plugin for my wordpress blog. If everything goes perfect over next few weeks, this plugin might be submitted in wordpress plugin’s directory.

Jaxl BOSH Support Framework
Jaxl BOSH support comprise of three main parts:

  • jaxl.jquery.js: JQuery extension written for Jaxl bosh support
  • jaxl4bosh.class.php: Connection manager in PHP
  • jaxl UI: Integrated UI framework for changing your application skin on the fly. Your application skin can be a simple facebook style chat bar (as on this page) or chesspark style whole html page

jaxl.jquery.js is responsible for initiating and maintaining a connection between the browser and the PHP connection manager. While jaxl4bosh.class.php implements the BOSH protocol and maintain a persistent connection with the jabber server.

jaxl.jquery.js provide a few basic methods like:

  • jaxl.connect: Call for initiating the connection
  • jaxl.sendMessage: Call for sending a message to other jid’s
  • jaxl.ping: Call to maintain the connection and gather any incoming data
  • jaxl.disconnect: Call for disconnecting

jaxl4bosh.class.php provide wordpress style filter/hooks which can be used to modify every incoming and outgoing messages.

  • jaxl_pre_connect: Call to perform initialization before jaxl connects to jabber server
  • jaxl_post_connect: Call to perform shutdown after jaxl is connected to jabber server
  • jaxl_send_message: Call to perform actions on outgoing messages from jaxl
  • jaxl_recv_message: Call to perform actions on incoming messages to jaxl
  • jaxl_send_presence: Call to perform actions on outgoing presence from jaxl
  • jaxl_recv_presence: Call to perform actions on incoming presence from jaxl
  • jaxl_pre_disconnect: Call to perform initialization before jaxl disconnects to jabber server
  • jaxl_post_disconnect: Call to perform shutdown after jaxl is disconnected to jabber server

Jaxl and WordPress
Using Jaxl bosh support require you to only edit the configuration file. Here are the config variables:

        // JAXL config
        define('JAXL_BOSH_HOST', 'localhost');
        define('JAXL_BOSH_SERVER', 'localhost');
        define('JAXL_BOSH_URL', 'http://localhost:7070/http-bind/');
        define('JAXL_ADMIN_JID', [email protected]');

You can configure Jaxl to use any of the available public xmpp services. However, I choose to host my own jabber server for my blog.

JAXL_ADMIN_JID is the admin jid to which Jaxl should route all incoming messages, added specifically for wordpress related requirement. PHP connection manager can be extended to route different chat sessions to different admins.

jaxl_recv_message handler is used to embed smiley’s and youtube videos by parsing the incoming chat messages.
jaxl-bosh-support-hook-demo-youtube-smiley

A few other hooks like jaxl_post_connect are used to notify JAXL_ADMIN_JID about the newly connected user.

Admin Screen
Below is a screen shot of how an admin desktop will look like while chatting with his site visitors:
Admin-screenshot-jaxl-bosh-support

Let me know if you are having any issues chatting using the chat bar at the bottom of the page. Code and installation might be buggy at times, and would appreciate any help from you on it.

Get real time system & server load notification on any IM using PHP and XMPP

There are various system and server related information which server administrators always need to have as soon as possible, infact I must say in real time. There are several open and closed source softwares in the market which can generate almost real time notifications for you. Most famous one being Nagios. In this blog post I will discuss, how to generate real time system notifications using PHP and XMPP. Specifically, I will present sample script using Jaxl (Jabber XMPP Client Library) for generating real time system load notifications, which can be received using any Instant Messengers.

/proc/loadavg
We will be using system /proc/loadavg file to get real time system load information. If you are unaware about this file, here is in brief how this file is helpful to us:

sabhinav:~# cat /proc/loadavg
0.22 0.12 0.09 1/68 12621

where first three columns measure the CPU and IO utilization of last one, five and 10 minute periods. The fourth column shows the number of currently running processes and the total number of processes. The last column displays the last process ID used.

jaxl4serveradmins.class.php
We will be using Jaxl PHP client library for handling the XMPP part. jaxl4serveradmins.class.php is an extension to Jaxl, providing various server administration helper function. Below is the code for server administration extension:

  include_once("xmpp.class.php");

  define('JAXL_SERVER_ADMIN', [email protected]');
  define('JAXL_SERVER_LOAD_POLL_INTERVAL', 10);

  class JAXL extends XMPP {

    function eventMessage($fromJid, $content, $offline = FALSE) {
    }

    function eventPresence($fromJid, $status, $photo) {
    }

    function eventNewEMail($total,$thread,$url,$participation,$messages,$date,$senders,$labels,$subject,$snippet) {
      // Not used here. See jaxl4gmail.class.php for it's use case
    }

    function setStatus() {
      // Set a custom status or use $this->status
      $this->sendStatus($this->status);
      print "Setting Status...n";
      print "Donen";

      $this->addJob(JAXL_SERVER_LOAD_POLL_INTERVAL, array($this, 'parseServerLoad'));
    }

    function parseServerLoad() {
      $loadavg = file_get_contents('/proc/loadavg');
      $this->sendMessage(JAXL_SERVER_ADMIN, $loadavg);
    }

  }

I have utilized addJob() method provided by Jaxl library, using which you can specify a callback to be called after every N seconds (in short a periodic cron). Here we add a periodic job to be runned every JAXL_SERVER_LOAD_POLL_INTERVAL seconds. parseServerLoad() method is called as the callback function.

$this->addJob(JAXL_SERVER_LOAD_POLL_INTERVAL, array($this, 'parseServerLoad'));

To keep the demo simple, I am simply sending the content of /proc/loadavg file as a message to server admins.

    function parseServerLoad() {
      $loadavg = file_get_contents('/proc/loadavg');
      $this->sendMessage(JAXL_SERVER_ADMIN, $loadavg);
    }

Running it for your servers:
Follow the following steps to get this started on your server (only Unix, no Windows):

  • Checkout from Jaxl trunk
    sabhinav:~# sudo svn checkout http://jaxl.googlecode.com/svn/trunk/ jaxl-read-only
  • Enter checked out directory
    sabhinav:~# cd jaxl-read-only
  • Enter your server admin IM contact details
    sabhinav:~# sudo vim config.ini.php
    define('JAXL_SERVER_ADMIN', [email protected]');
  • Enable server administration extension
    sabhinav:~# sudo vim index.php
    include_once("jaxl4serveradmins.class.php"); // include_once("jaxl.class.php");
  • Wroom Wroom, start Jaxl
    sabhinav:~# sudo php index.php
    Starting TLS Encryption...
    Attempting PLAIN Authentication...
    Starting Session...
    Requesting Feature List...
    Requesting Roster List...
    Setting Status...
    Done
    

Tail the jaxl log file in case you are facing any difficulties in the setup.

sabhinav:~# tail -f log/logger.log

You should also consider adding /proc/ directory under open_basedir in php.ini file.

Is it working?
If all is well configured server admins will start getting notifications every 10 seconds which is default value for JAXL_SERVER_LOAD_POLL_INTERVAL.
Jaxl4serveradmins.class.php example screenshot for system load

Writing custom notifications
Above I demonstrate how we can use XMPP and PHP to generate real time system notification. However, you may want to modify parseServerLoad() method to send notifications only when the server load exceeds a certain value. You may also want to add other methods which can notify you of various System and Server level parameters in a similar fashion. Below are a few useful system administration commands:

sabhinav:~# free -m
sabhinav:~# vmstat 1 20

Is it really real time?
Since, parseServerLoad() method polls for /proc/loadavg file every 10 seconds, this is not exactly real time. However you can configure JAXL_SERVER_LOAD_POLL_INTERVAL to make it poll faster. You can also use libevent extension in PHP to make it real time in real sense.

Do let me know if you write any interesting functionality, I will be more than happy to include it as a part of current extension.

Get lyrics for any song using XMPP and PHP right into your IM – Add [email protected]

XMPP is soon finding it’s way into real time applications other than just chat. I have combined JAXL (Jabber XMPP client library written in PHP) and the API from lyricsfly.com to build a real time chat bot which can assist you with lyrics for any song. You can start using it by simply adding [email protected] to your IM account (e.g. Gtalk, Jabber etc). In this blog post, I will explain in brief the working of lyricsfly bot and how you can integrate XMPP into your own application.

Try out [email protected]
Follow the following steps to get the bot working for you:

  • Login to your gtalk account using any of the IM available
  • Press Add Contact
  • Add [email protected] as your chat buddy
  • Send a chat message in following format “Song Title – Song Artist” e.g. “one – metallica”
  • You should see something like this: lyricsfly@gtalkbots.com Demo for "one-metallica"

Working of [email protected] with Jaxl
Here is in brief the working of lyricsfly bot using Jaxl client library:

  • When someone sends a message like “one – metallica” to the bot, eventMessage() method is called inside jaxl.class.php
  • eventMessage then extracts the song title and artist name from the message using PHP explode. Filter the title and artist names for allowed characters.
  • eventMessage also calls lyricsfly API and fetch the lyrics. Finally it sends the lyrics as message to requester.
  • eventMessage also uses memcached to cache the lyrics. It decreases both response time and load on lyricsfly servers
  • Bot also keeps a count of number of queries from a particular user. Since it is still under development, currently there is a limit on number of lyrics you can fetch in a single day.

Making your own custom bot

  • Checkout latest from the trunk
    sabhinav$ svn checkout http://jaxl.googlecode.com/svn/trunk/ jaxl-read-only
  • Edit config file with your bot username, password and jabber servers
  • Run from command like
    php index.php
  • To customize the bot modify eventMessage and eventPresence methods of Jaxl class inside jaxl.class.php

For a full fledged running bot example code, edit index.php and include jaxl4dzone.class.php instead of jaxl.class.php and re-run the bot.

Have fun and enjoy singing songs along with the lyrics.

WordPress style “Duplicate comment detected” using Memcached and PHP

If you have a knack of leaving comments on blogs, chances are you might have experienced a wordpress error page saying “Duplicate comment detected; it looks as though you’ve already said that!“, probably because you were not sure that your comment was saved last time and you tried to re-post your comment. In this blog post, I will put up some sample PHP code for Duplicate comment detection using Memcached without touching the databases. Towards the end, I will also discuss how the script can be modified for usage in any environment including forums and social networking websites.

Duplicate comment detection using Memcached
Here is a php function called is_repetitive_comment which return some useful value if the comment is repetitive, otherwise FALSE.

<?php

        define('COMPRESSION', 0);
        define('SIGNATURE_TTL', 60);

        $mem = new Memcache;
        $mem->addServer("localhost", 11211);

        function is_repetitive_comment($comment, $username) { // username can be ip address for anonymous env
                                                              // for per blog/forum checks pass forum id too
                                                              // for multi-host using same memcached instance, pass hostname too
                                                              // for restricting post of same comment, don't pass username
                $comment = trim($comment);
                $signature = md5(implode('',func_get_args()));

                global $mem;
                if(($value = $mem->get($signature)) !== FALSE) {
                        error_log($signature." found at ".time());
                        return $value;
                }
                else {
                        $value = array('comment' => $comment,
                                       'by' => $username,
                                       /* Other information if you may want to save */
                                      );
                        $mem->set($signature, $value, COMPRESSION, SIGNATURE_TTL);
                        error_log($signature." set at ".time());
                        return FALSE;
                }
        }

?>

Is it working?
Lets verify the working of the code and then we will dig into the code:

  • Save the sample code in a file, name it index.php
  • Towards the end of the script add following 3 line of code:
            var_dump(is_repetitive_comment("User Comment", "username"));
            sleep(5); // Simulating the case when a user might try to post the same comment again knowingly or unknowingly
                      // Similar kind of check is done in wordpress comment submission (though without memcached)
            var_dump(is_repetitive_comment("User Comment", "username"));
  • Run from command line:
    sabhinav$ php index.php
    6105b67d969642fe9e27bc052f29e259 set at 1262393877
    bool(false)
    6105b67d969642fe9e27bc052f29e259 found at 1262393882
    array(2) {
      ["comment"]=>
      string(12) "User Comment"
      ["by"]=>
      string(8) "username"
    }
  • As seen, function is_repetitive_comment returns bool(false) for the first time. However, after 5 seconds when same comment is being submitted it throws back some useful information from previous submission.

Working of is_repetitive_comment
Here is in brief, how memcached is used for duplicate comment detection by the script:

  • SIGNATURE_TTL defines the time limit between two similar comment submissions. Default set to 60 seconds
  • is_repetitive_comment takes two parameter namely the comment itself and the username of the user trying to post the comment.
  • The function create a signature by combining the passed parameters and checks whether a key=$signature exists in memcache
  • If key is found, it means same user has posted the same comment in past SIGNATURE_TTL i.e. 60 seconds. Function simply return back the value set for the key from memcache
  • However, if key is NOT found, user is allowed to post the comment by returning FALSE. However function also sets a key=$signature into memcache

The value of key=$signature depends upon your application and use case. You might want to save some useful parameters so that you can show appropriate error message without hitting the databases for anything.

Extracting more from the sample script
Here is how you can modify the above sample script for various environments:

  • If you are performing repetitive comment check in an anonymous environment i.e. commenter may not be registered users, you can pass commenter’s ip address instead of username
  • If you serve multiple sites out of the same box and all share the same memcached instance, you SHOULD also pass site’s root url to the function. Otherwise you might end up showing error message to wrong users
  • If you want to restrict submission of same comment per blog or forum, also pass the blog id to the function
  • If you want to simply restrict submission of same comment through out your site, pass only the comment to the function

Let me know if you do similar tiny little hacks using memcached 😀