Monthly Archives: January 2008

persistent web apps in PHP

Recently, I’ve been working in an environment which uses a lot of Java, so I got to reflect on the differences between PHP and Java.

One of the more obvious differences is that in Java’s case, it is possible to start up a persistent server which runs and runs even if there is no client keeping it alive with http requests. This is in contrast with the usual PHP setup, where each client request sparks up a new instance of a “page”, which is only alive for the duration of the request.

The problem with the stateless method (where instances are alive only temporarily) is that this makes it tricky to build larger application which rely on persistent data storage or potentially time-consuming algorithms.

As an example, consider the case of an IRC program, where it is required that the server keep a store of messages, which are doled out on request to a web client.

With a stateful engine, a Java service, for example, the messages can be kept in-memory, and only one instance of the message server needs to exist. Each request is handled pretty much instantly, and there is no pause while database connections are set up and polled.

With a stateless system, the default PHP setup, it is required that the messages be stored external to PHP, as PHP’s memory lasts only as long as the HTTP request. This means that every request from the client involves loading up the script, parsing, connecting to DB, retrieving, updating, and sending back to client. A lot slower than the Java method, I think you’ll agree.

This disturbed me as I really like PHP, and Java’s /such/ an awkward language to work with (every change involves recompiling, redeploying, and a lot of waiting).

Thinking about it on the way to work today, I realised that PHP /is/ capable of bing stateful. You just have to remember that PHP is not confined to the web – you can have a CLI engine running in PHP that is persistent.

The key to this is that the CLI script keeps the message store in-memory (like the Java service), and communicates with the client through a web-based PHP “gateway”.

IRC server <--> PHP Gateway <--> Client

The gateway step is not actually required, but helps to filter out the rubbish that might come through if the IRC server was connected directly to the net.

You start the IRC server running as a script from the console (php server.php), and leave it running. CLI scripts have no timeout, so it will keep running until you manually turn it off.

The client requests information from the gateway, which connects briefly to the running instance of the server through a socket, and returns the message to the client.

To illustrate this, try this script out from the console:

<?php

$port=10001;
$max_messages=3;

// initialise chat messages

$msgs=array();

// open socket

$s_socket=socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
socket_bind($s_socket,'127.0.0.1',$port);
socket_listen($s_socket,10);

// start the msg loop

while($c_socket=socket_accept($s_socket)){

  // what messages are being retrieved?
  $from=socket_read($c_socket,1024);
  if($from=='')$from=0;
  else if((int)$from != $from){
    // syntax error - first line should be a number or blank
    socket_close($c_socket);
    continue;
  }
  else $from=(int)$from;

  // send retrieved messages to client
  $retrieved=array();
  $highest=0;
  for($i=0;$i<count($msgs);++$i){
    $highest=$msgs[$i][0];
    if($highest<$from)continue;
    $retrieved[]='["num":'.$msgs[$i][0].',"msg":"'.addslashes($msgs[$i][1]).'"]';
  }
  socket_write($c_socket,'{'.join(',',$retrieved).'}');

  // get sent message
  $msg='';
  do{
    $m=socket_read($c_socket,1024);
    $msg.=$m;
  }while($m);

  // add sent message to message store
  if($msg!='')$msgs[]=array($highest+1,$msg);

  // restrict the size of the message store
  while(count($msgs)>$max_messages){
    array_shift($msgs);
  }

  socket_close($c_socket);
}

socket_close($s_socket);

?>

Run the above in one terminal, then open another terminal (or tab) and connect to it (telnet 127.0.0.1 10001). Press enter (to indicate you want all existing messages), then type “test”, press enter, then close the connection (^], then quit).

The first time you do it, you’ll get an empty object returned ({}). The second time, you’ll receive the first message that was sent. the third time, you’ll receive the first two messages.

This has some really cool implications – you can now write a continuously updating programming which doesn’t require cron and the inevitable timely bashing that it does to the system. Cron is periodic, but a lot of people choose the same periods for everything. Imagine what would happen to your email server if everyone chose to download their email at exactly 1pm every day but no other time? Instead, a continually running engine allows a more smooth flow to develop.

It also means that your application can be kept slim, with the server and gateway code kept distinctly separate. This has the added value that it speeds up the whole thing – when connecting to the server, the server is already running, so the only code needed to load up and run is the code that retrieves the message via the socket and passes it on, and with a caching webserver (Zend, for example), this will be faster again.

The above was just one example of how to do this. There may be others. This is most likely not a new idea to a lot of people, but I didn’t see it written anywhere so I thought I needed to write it.

kfm tutorials, languages, plugins, etc

Interesting. I just came across a small tutorial in Thai, showing how to install KFM. I had come across another previously in greek, but it’s exciting to see a non-european language version.

On the languages front, KFM is still spreading. There is a Persian translation, as well as Swedish. The Persian is particularly exciting because it’s the first right-to-left language in KFM. I’m not sure if it’s correct, as I don’t speak Persian and the translator hasn’t supplied corrections yet, but it’s exciting none-the-less.

I haven’t had the time recently to work on KFM, but Benjamin ter Kuile has been doing a sterling job creating a plugin framework, allowing external developers to eventually write plugins for their own KFM installations without needing to understand all of KFM. If you want to try his work, download a copy of KFM from SVN, and try some of his plugins, or build your own!.

2008 plans

yes. another resolutions page. I’ll call them plans, though, as “resolutions” sounds a bit certain. in my experience, nothing is certain, even promises.

so, my plans:

  • lose a half-stone. when I married Herself, I was 12 stone. this was probably partly caused by the anti-depressants I was on at the time. since then, it took me a few months to manage to cut down to 11 stone. my ideal weight is more like 10 stone, but I’m finding it incredibly difficult to do that – I just seem to be stuck at 11. so, this year’s plan is to get down to 10.5.
  • build the new robot – I want a very small form-factor machine (gumstix or linutop). it should have caterpillar tracks, a robotic arm, and a cutting tool. my current bot is about 9’x14′. the new one should be at most 6’x6′. the software is not yet complete, but at least this will get the hardware out of the way
  • get my finances back under control. for the last few years, I’ve had negative values in almost all of my bank accounts. about time I managed to fix that. I have one account under control by basically denying myself access to it and setting up a standing order into it. the same plan should work with everything else. the plan is to on average raise the total value of each account by a set value every month. this value (none of your damned business 😉 ) should be measured on a specific day each month.
  • build a collapsible mini-ramp. I can’t make it to the local skate-park very often, so the plan is to build something that I can wheel out to the garden when I feel like some exercise. it should be big enough that I can use my bike on it as well as my skateboard.

notice that none of these are vague. it’s been shown that when a resolution is vague, it usually does not happen. an exact plan, though, gives solid goals that can be reached.

damn you, guitar hero

my wrists are in pain. I’ve a lump of calloused flesh on my right thumb. my fingers are hyper-sensitive. and yet I want to do it again.

I’ve beaten Easy and Moderate and am half-way through Hard.

most of the songs in Hard are …hard… it’s kind of annoying that you have to pass every single song in the playlist to win, where in the Moderate and Easy levels, you had to pass maybe 3/4 of them. if I was playing live on stage, I think I would have a choice of what to play or not…

an annoyance in the game is that I (like a lot of players, I imagine) can actually play guitar. I keep trying to play notes that are not actually mapped on the tab, and you can’t show a bit of flair or improvise with the timing, which I like to do when playing an actual guitar.

given all that, I’ve managed to reach The Knights Of Cydonia. that is one bugger of a song. as attested by another player, the most punishing part of the song is the Amending Chorus and the Galloping Triplets – two sections of finger-destroying repetition. it’s not even that they’re particularly hard – it’s just that they sap the energy from your hands and make you swear off listening to Muse for fear of flashbacks.

a pretty cool part of the song comes near the beginning, where you get to do some incredibly fast picking. I’m not sure that Muse in reality play this song so difficultly. if so, though, Matthew Bellamy, if I had a hat, it would currently be off.

some people say that the key to getting through that section is not even to try – store up some star power and use it when you get there so the audience won’t hear all the mistakes you make. I think I’ll just keep trying. when I get to Expert level I’m sure it will be even harder…