logo

ShrimpWorks

// why am I so n00b?

A long time ago, in a galaxy not far away, I created a very small application named SaveScreen. Today I’m rather pleased to release a much-improved SaveScreen 2.

A couple of anti-virus applications complained that the .dll file distributed with SaveScreen which enabled detecting when “Print Screen” was pressed, was a virus or malware of some sort, so even I was unable to use SaveScreen, which made my cry.

Finally fed up, I set out to resolve the situation by creating a brand new application which did not rely on random keyboard hooks and stuff. The result is SaveScreen 2.

In addition to no longer being flagged as a virus, SaveScreen 2 features direct ImageShack posting (complete with automatic forum code creation and thumbnail support), and FTP uploads of screenshots. Something which may be rather handy (just don’t take a screenshot of your bank statement then complain when the whole world is exposed to it - use with care). Also, it can save screenshots in per-application folders, making organisation somewhat neater.

Heh, I guess there are already plenty of tools out there which do this sort of thing already (never seen them personally, but then I’ve never looked either, heh), but this only took me half an evening to throw together anyway.

Basically, it’s a Python (uses youtube-dl) and PHP-powered web-based YouTube video downloader and converter, you just stick in the URL to a YouTube clip you want to save, and it will download it and offer it for download as an MPEG which you can save on your PC and play in all it’s low-quality glory whenever you want.

Basically it automates the following, which can be run on any Linux PC:

# youtube-dl.py -o myvid.flv http://www.youtube.com/watch?v=123abc # ffmpeg -i myvid.flv -ab 56 -ar 22050 -b 500 -s 320x240 myvid.mpeg

As an added benefit, it stores a complete history of downloaded clips, so you and others can re-download them at any time without having to do the whole fetch/convert process over again. Plus it uses a nifty fake AJAX waiting effect :P.

Requires Linux with ffmpeg, Python 2.4+, and PHP 4.3+.

Since the XBox Live “GamerCards” are so nicely exposed, there’s really no reason not to have a DynaBar plugin for it, now is there.

I’ve noticed a few GamerCards claiming to be in “userbar” format, however they do not follow userbar standards in layout, dimensions, or fonts. So, soon you too can have a lovely dynamic standards-compliant GamerScore userbar such as this:

After the release of the “Dumb Image Browser”, (which worked/works very well for what it’s supposed to do), I thought of prettying it up a bit, and adding some extra features.

The result is the Nice Image Browser. It’s vastly improved in terms of visuals, as well as offering features like easier browsing around the galleries, easy creation of new galleries, and uploading files directly from the browser.

It maintains the same PHP5-powered, database-less, cache-less, auto-thumbnail generating system of the Dumb Image Browser, meaning it’s just as easy to get set up (copy the files to a directory you want to become your gallery).

Thanks to Korpse/k4y/K` for the new stylesheet used for displaying the thumbnails.

The ReadMe includes usage and setup instructions. Happy image browsing! :)

Hmmmmm, long time no update. That’s not to say I haven’t been busy recently.

Last month, we released “UnWheel R5”, which seems to have become the (hopefully) final release. I’m pretty happy with it at the moment, all the major bugs are gone, multiplayer is working wonderfully and the online record system is churning records around at a mean rate (and those records still need a monthly rotation system applied, so still some work to be done there). I still haven’t decided if I want to do this all again in Unreal Torunament 2007 or not :).

Elsewhere, I’ve been playing around with DynaBar, and it’s grown a lot. The plugin system has been tweaked to allow better customisation options from the developer side, as well as having options added to improve the user interaction side of things. There are a whole crapload of other options available as well, multiple layers (supporting PNG graphics with alpha transparency), different scanline styles, text prefixes and suffixes, better caching options, etc. In addition, you can choose to have the background be a gradient blending between any two colours, horizontal or vertical, and you can create “groups”, which is a bunch of userbars animated (with fading/blending between bars), and they all remain fully dynamic. Speaking of dynamic, I’ve also added a whole load of plugins, from XFire, to more Last.FM options, to Battlefield 2 and TrackMania, and even RSS headlines and live game server status via Qstat.

I’ve put up a test system here as a sort of sandbox, so feel free to try out all the options and plugins, and if you have any suggestions or ideas for plugins, please let me know. In addition to the designer, there’s a browser available, which lets you easily build the animated groups mentioned above. Also, it all works with Internet Explorer now, which I didn’t bother fixing with the previous version (wasn’t meant to be such a “big” project :)). Source code package will be available as soon as some more testing is done.

In addition, I’ve been re-writing my online Dosage-powered comic viewer - Injector

  • again, this time it’s going fully “Web 2.0” (ZOMG!), so everything’s quite nice and quick. This project still needs a bit of work on the administration and installation side of things before it can see a release.

Aside from all that, I’ve also been slowly building a new UnrealZA site, using the Python-powered Django framework. It really is a wonderful thing. Please excuse me for a minute while I run away from a horde of crazy, twisted, Nevow fans (among others). Anyway, I’ll happily recommend Django any day of the week to anyone looking for a Python web framework.

I’ve also decided I don’t like the look of this site anymore, so I guess that’s another thing to go on my to-do list for the near future.

Created two very basic scripts this past week:

The first, a basic Image Browser:

Basically, I really hate trying to set up and use normal image publishing/gallery software. Something like Gallery is pretty nice and feature packed, but for putting a photo of your cat online, it’s pretty much a mission, with users, permissions, logins, galleries, categories, grouping, keywords, thumbnail options, etc, etc. I just want to upload a JPEG and say that’s the end of it, but still have ti browsable with some thumbnails that didn’t take me 10 minutes to create in Photoshop.

Anyway, yar. So I made this script. It’s actually a pair of scripts. A basic browser interface that simply goes through a directory, finds all images, links to them, and shows thumbnails of them via the second script - a basic thumbnail generator.

So ‘installation’ is simply dropping this pair of scripts into the directory you want to publish your images from, and it’s done. Any sub-directories will be navigable, so you can use them as ‘categories’ if you’d like. Since the thumbnails are generated on the fly as needed, there’s no database or anything, and adding a new image is as simple as dropping the file into your image directory.

The second script, is a Download Tracker:

Extremely simple again, simply does a count of hits on any file passed to the file.php script. The files can be located anywhere on the system (so if you really don’t want people getting at your files without going through the counter, they can be outside of your www published path).

Again, I was going for simplicity here, so there’s no massive upload manager UI, or snazzy hit monitoring UI, or a 5000 table MySQL database. It keeps track of the hits by simply storing them in a regular PHP array, and then serializing this array to a file. Next time the file it requested, the hit log file is loaded, then unserialized into the array, the array is updated and serialized again. :). So you’ll need to make sure the files.log file is writable by the web server (or the whole directory the tracker files are in). It also requires PHP5, unless you write replacement functions for file_get_contents() and file_put_contents() on earlier PHP versions.

Link to a file as follows: http://my-site.za.net/file.php?installer.exe, or even http://my-site.za.net/file.php?path/to/document.pdf

You can then view the hits and things via the file_stats.php which outputs a very basic tabular representation of the stats the hit log tracks.

Both of these packages’ code is pretty well documented, so if anything, they may be educational so you can build more exciting versions of these. However, as they are, they serve my needs, but just thought I’d share anyway ;).

Usage instructions are also within the code.

I’ve had to do quite a bit of stuff with images in Delphi recently (lots of manual drawing too), and discovered TCanvas’ TextOut method will only draw text onto one line, line breaks and newlines are ignored. Google search results suggested Windows’ DrawText function, however despite all the formatting and alignment flags it takes, it refused to draw text centred vertically.

Anyway, here’s a small-ish procedure which will take your multi-line text, and draw it centred on the canvas you pass it. You also need to pass the width and height of the canvas you’re drawing to. It assumes the font can everything else has been set by you, prior to calling it. Also, be sure “Graphics” is in your “uses” section.

procedure multilineCanvasText(canvas: TCanvas; text: String; width, height: Integer);
var
  textSize: TSize;
  lines: TStringList;
  i, blockHeight: Integer;
begin
  // lazy man's way of splitting text by line into a list (split by #13#10)
  lines := TStringList.Create;
  lines.Text := text;

  // see how high our block of text is going to be, based on the font the canvas
  // currently has set
  textSize := canvas.TextExtent('LOZL!');
  blockHeight := textSize.cy * lines.Count;
  blockHeight := blockHeight;

  // go through each line and output it
  for i := 0 to lines.Count - 1 do
  begin
    // we need the width of each line, so we can center it on the canvas
    textSize := canvas.TextExtent(lines[i]);
    // render the text
    canvas.TextOut((width div 2) - (textSize.cx div 2),
                   (height div 2) - (blockHeight div 2) + (textSize.cy * i),
                   lines[i]);
  end;
  freeAndNull(lines);
end;

Guess it shouldn’t have taken so long for me to get around to doing this, but at least it’s done now.

Attached to this post you’ll find a zip file, containing a small example application which allows you to spawn PyODE physics-enabled cubes with the middle mouse button into a PyOgre world. You can then bounce and roll the cubes around by holding the left or right mouse buttons.

The code is fairly straight-forward, and I’ve included quite a number of comments. Should be easy enough to follow what’s going on if you’ve been through the PyOgre tutorials.

A note of performance and stability - you can safely spawn loads of cubes as long as there are not too many collisions going on at once (after around 50 cubes, things start to get really sluggish if there are too many inter-cube collisions going on). In practice though, I doubt you’d need that many collisions happening at any one time. Also, If you make a large pile of cubes, lift them all up, and let them fall down together, it seems to bomb out as there are too many collisions happening when they all land on top of eachother at once. I haven’t debugged this very much, so I’m not sure yet if it’s a ODE limitation, or something bad I’m doing in the code. If anyone works it out, I’d be interested to know.

Please don’t ask for advice on stuff like per-polygon collisions, terrain collision and the like, I have not really messed with this beyond the state of this example. Once you get the basics going after checking out the example, I’m sure a few questions shot off at the PyOgre Forums would turn up more useful results than asking me :).

Have fun ;).

As we all know, PNG images are so much cooler than BMP images. Especially with alpha channels.

A while ago, I found this rather spiffy PNG library for Delphi, which allows you to load PNG files into a TPicture or similar, complete with alpha channels. Generally, it works simplest with TImage, however being a TGraphic subclass, you can do all sorts of drawing and everything else on it.

ANYWAY, I wanted to be able to use these things on buttons (standard TSpeedButton and TBitBtn), however their Glyph property is a TBitmap, preventing us from doing a simple Button.Glyph.LoadFromfile and loading a PNG file. The other option is to load up the PNG on it’s own with a TPNGObject, and assign it to the glyph property, however the alpha gets buggered.

So I came up with a crackful work-around (as I’m finding 90% of all Delphi coding is):

procedure pngGlyph(Btn: TControl; Img: String);
var
    PNG: TPNGObject;
    BMP: TBitmap;
begin
    PNG := TPNGObject.Create;
    BMP := TBitmap.Create;

    try
        PNG.LoadFromFile('path\to\glyphs\'+Img+'.PNG');   // Update the path to your .png files, or update this to get them somewhere else.

        BMP.Width := PNG.Width;
        BMP.Height := PNG.Height;
        BMP.Canvas.Brush.Style := bsSolid;
        BMP.Canvas.Brush.Color := clBtnFace;
        BMP.Canvas.FillRect(Rect(0, 0, PNG.Width, PNG.Height));
        BMP.Canvas.Draw(0, 0, PNG);
        BMP.Canvas.Pixels[0, BMP.Height-1] := clBtnFace;

        if (Btn is TSpeedButton) then
            (Btn as TSpeedButton).Glyph.Assign(BMP);
        if (Btn is TBitBtn) then
            (Btn as TBitBtn).Glyph.Assign(BMP);
    finally
        PNG.Free;
        BMP.Free;
    end;
end;

To use it, you call it like pngGlyph(SpeedOrBitButton, 'glyphname');, and the procedure will hack your button’s glyph into something that looks nice. You can use fully alpha-enabled PNG files, and they should look right.

Of coarse it would be better to create a new button type with this procedure inside that, so you don’t have to call this for every button you want to add a PNG to, but I don’t really feel like re-adding a million buttons, it’s quicker for me to do a million procedure calls :).

Heh :D

So I’ve started work on my own small RSS aggregator for some or other web project I may or may not actually complete. And no, it’s nothing like Gregarius, it’s more of an ‘internal function’ of a larger project.

So anyway, after checking out the various RSS version specs and things, I hunted down as many feeds as I could to get an idea of the kinds of data I’m going to end up sifting through.

Wow. Despite the fact that there are standards out there doesn’t seem to mean much. Nearly every feed is a world apart from the next one, either throwing in millions of useless custom tags, renaming standard tags to some other random thing that made sense to the author and nobody else, leaving out loads of actual useful information, mixing and matching the specs as they feel the urge, and a million other randomnesses.

Anyway, on the way to making sense of it all, I fed some of them through MagpieRSS, which actually does a fairly reasonable job of making them a bit more sane. Still, I have to guess a lot of fields and things, and pretty much hope for the best.

At the moment, people’s RSS feeds generally seems more psychotic than some of their use of HTML.

Well, in the interests of Monster Hunt surviving a bit longer, I’m releasing the full UnrealScript source code.

Included is a basic license document, outlining in simple terms what you may and may not do. Basically, you may make any kind of MH mod or ‘sub-mod’, however you must give due credit for the original creation. Even if it’s very basic, please read it if you intend using it for creating a mod.

You’ll find the file at the end of this post… Have fun :)

MonsterHuntSource.zip

I was browsing around the BeyondUnreal Forums the other day, and came across an 11 page thread, with around 720 replies, about Monster Hunt. Interested to see what’s up, I checked the CSports rankings for Unreal Tournament, and was shocked to find MH is the #4 most played UT gametype in the world. Coming in after CTF, DM, and TDM.

Seems people have been making maps like nuts, there seem to be over 300 of them, there are a few mutators and mods available for it as well. I found there’s even a pretty large fansite, Planet Monster Hunt.

Not too bad for a mod I thought I had retired nearly four years ago ;).

My idea for implementing non-physics physics into my little game framework didn’t work out too well, so I gave in and took a look around for options.

It seems only ODE is available to Python, via PyODE. Not many [open source] physics engines seem to have Python bindings, which I find rather odd.

As it turns out, it isn’t actually all that of a mission to get ODE and Ogre working together, and the results I’ve got so far are quite acceptable. I can spawn loads of cubes (of varying sizes) and throw them around the scene and they bounce and jump around in a suitable fasion.

PyODE and PyOgre playing nicely

I haven’t tried with balls or polygon-accurate stuff yet, that’s next on the to-do list. I also intend writing a short how-to for PyODE and PyOgre integration at some point, as I was a little confused to start with, not knowing quite where or how to begin, and there is no PyODE/PyOgre example code floating around to reference.

EDIT: Example using PyODE and PyOgre now available

It seems as though the guys at work are seriously looking into the option of doing some game development next year some time, and they’ve been busy checking out various engines and frameworks to help with this. Despite being the only person at work who plays games seriously, and my history of developments on the Unreal engine, I haven’t really been included much with what’s going on.

However, since game development (of any kind) is the number one thing I’d like to be doing with my life (NOT point of sale systems!!), I’ve decided to involve myself anyway :D.

I have been playing around with a couple of game and physics engines (games being discussed are potentially vehicle-based), and Irrlicht particularly seems rather nice. Korpse however, suggested I take a look at Ogre. I was very pleasently surprised to find the PyOgre project, which exposes about everything Ogre can do, to Python (you don’t even need the Ogre SDK, it works completely on it’s own), and seems very well supported. I’m a lot more comfortable with Python than I am with C++ :).

The only down side, is that Ogre is not a complete game engine, but rather simply a graphics engine. Meaning, I’ll have to work out how to add sound, physics, advanced input options (Ogre does support keyboards at least), etc on my own. There are a lot of options available for all of those, so I’m not really worried about it at the moment.

I’ve begin putting together a bit of a basic framework for myself, trying to base how things work around how UnrealScript works and interacts with classes and objects. It’s working out pretty cool, thanks again to Python.

As a test project, I’ve decided to put together a sort of basic World War II flight sim. All you need really is a model, some terrain, and basic flight physics (which I plan on simulating without the use of a physics engine, in a similar fasion to how I did some stuff in Unreal Tournament [pre-Karma]).

Since the scripting is going well, I decided to take a shot at a quick model. I came across Wings 3D – a simple “subdivision modeler”. Basically you start off with whatever primitive shape (cube, spheres, cylinder, etc) you think will suit what you’re going to build, and stretch and warp it into the final product. I’ve never modeled like this before, but it works surprisingly well.

After 2 hours work, I got the following result from a 16-sided cylinder:

There are quite a number of rather ugly polygons, but it was a learning experience :).

Update: DynaBar 2 is available, the download link below is out of date.

Finally got around to making a proper release of something :).

Presenting DynaBar, a PHP script which can create dynamic images through the use of plugins, inspired by the Userbars.com website.

I thought it would be cool to be able to have userbars with dynamic data in them, stuff like game server status, stats, etc., etc. to make them a little more exciting. I also wanted to learn a bit more about PHP’s image manipulation, so this proved a good oppertunity for that.

Basically, the whole thing works off a plugin system, which lets you drop in a PHP script (the plugin), set up a config file (the userbar), and link to an image. DynaBar then goes about loading the plugin, requesting it’s data (so it goes off and collects stats, or whatever), and building the final image (putting on the [optional] scanline effect, glossy shine, and layering the text data from the plugin on all of that).

I’ve also created a small designer script, which allows you or any users to create new userbars using plugins or whatever, with their own images and content, in a simple wizard-like interface. The end result is ready-to-use forum or HTML code. :).

Here are some examples, using plugins included in the package:

Image lost in time Simple, plain text (nothing dynamic about it).

Image lost in time This one queries LastFM for which song I’ve played most recently in my media player.

Image lost in time Finally, here we have Battlefield 2 stats, coming from BF2Tracker’s clan XML feed.

Grab the download from the bottom of this post. Please read the README in the doc/ directory.

I’ve had a couple of questions regarding my Battlefield 2 Stats in Python post, and how it may be possible to do the same in PHP, so I thought I’d add an update for that.

Simple PHP code for Battlefield 2 Stats retrieval:

    ini_set("user_agent","GameSpyHTTP/1.0");

    $info = "per*,cmb*,twsc,cpcp,cacp,dfcp,kila,heal,rviv,rsup,rpar,tgte,dkas,dsab,cdsc,rank,cmsc,kick,kill,deth,suic,ospm,klpm,klpr,dtpr,bksk,wdsk,bbrs,tcdr,ban,dtpm,lbtl,osaa,vrk,tsql,tsqm,tlwf,mvks,vmks,mvn*,vmr*,fkit,fmap,fveh,fwea,wtm-,wkl-,wdt-,wac-,wkd-,vtm-,vkl-,vdt-,vkd-,vkr-,atm-,awn-,alo-,abr-,ktm-,kkl-,kdt-,kkd-";

    $pid = '43595724';
    $data = file("http://bf2web.gamespy.com/ASP/getplayerinfo.aspx?pid=".$pid."&info=".$info);

    $stats = array_combine(explode("\t", $data[3]), explode("\t", $data[4]));

    printf("%s has %s kills and %s deaths and a score of %s", $stats['nick'], $stats['kill'], $stats['deth'], $stats['scor']);

Note that if you’re not using PHP5, you’ll need to add the following drop-in replacement for the “array_combine” function:

    function array_combine($keys, $vals) {
        $i = 0;
        foreach ($keys as $key) {
            $newarray[trim($key)] = trim($vals[$i++]);
        }
        return $newarray;
    }

It’s also important to note that while at the time of writing this, this method of retrieving stats works, EA, DICE and GameSpy are supposedly working on a new XML-based stats system for BF2.

Updated: Since this was written, some things changed with the stats system, and the GameSpy application requires you to pass a bunch of columns you want info for. This can help customise the data you get back, so you only request what you need. I’ve included all the columns in the $info variable, which you can customise. Make sure it contains only valid columns, or you won’t get any data back at all.

For info on what to do with the stats, and what all the columns etc. mean, check out the BF2 Technical Wiki.

Ever since installing BattleField 2, I’ve had a problem with taking screenshots. Basically, the game completely freezes up when I press whatever key is assigned to screen captures, and I need to reset my computer completely. Also, I seemed unable to use Fraps to make screen captures since the game seemed to be blocking all requests to whichever keys I assigned to Fraps’ capturing options.

I decided to rather just create my own utility. A simple application that hooks into the “Print Screen” key’s press, so when you press Print Screen, this app takes the image out of the clipboard, and will write it to a folder as a JPEG image. You can customise both the output location and the JPEG compression quality. The images are named after the current date and time.

It doesn’t work only for games, ANY time you press Print Screen, a screenshot will be saved. I think that could actually be pretty useful.

Yes, there are a million screen grabbers for Windows out there, but writing something yourself is both educational, and you know exactly what it’s doing. Also, I now have a single screenshot button for games, and everything else as well :D.

Note this may not work for all games, as some games tend to dump quite a mess to the clipboard when attempting a Print Screen.

This post also serves as a test for the attachment plugin for WordPress I recently installed ;).

Yes, so everyone’s obsessed with checking their BF2 stats these days ;).

Anyway, I wanted to give my Supybot IRC bot (“Nooblet” on Shadowfire) the ability to check my own and other people’s stats whenever they felt like it. I came up with something like this:

import urllib2
from string import split
from time import time

# the columns you want to request data for. comma-separated string.
info = 'per*,cmb*,twsc,cpcp,cacp,dfcp,kila,heal,rviv,rsup,rpar,tgte,dkas,dsab,cdsc,rank,cmsc,kick,kill,deth,suic,ospm,klpm,klpr,dtpr,bksk,wdsk,bbrs,tcdr,ban,dtpm,lbtl,osaa,vrk,tsql,tsqm,tlwf,mvks,vmks,mvn*,vmr*,fkit,fmap,fveh,fwea,wtm-,wkl-,wdt-,wac-,wkd-,vtm-,vkl-,vdt-,vkd-,vkr-,atm-,awn-,alo-,abr-,ktm-,kkl-,kdt-,kkd-'

# this is my BF2 ID. You can also query the stats server with "nick" rather than "pid", but I've had problems with some characters
pid = '43595724'

opener = urllib2.build_opener()
opener.addheaders = [('User-agent', 'GameSpyHTTP/1.0')]  # otherwise GameSpy's servers will block your request
webData = opener.open('http://bf2web.gamespy.com/ASP/getplayerinfo.aspx?pid=%s&info=%s&nocache=%s'%(pid,info,round(time()))).read()

statsData = split(webData, "\n")

cols = split(statsData[3], "\t")
data = split(statsData[4], "\t")

stats = dict(zip(cols, data))

# you now have a nice dictionary with a few hundred bits of stats data.
print "%s has %s kills and %s deaths and a score of %s" % (stats['nick'],stats['kill'],stats['deth'],stats['scor'])

Thanks to korpse and mithrandi for showing me the “zip” function. It takes the list from the first parameter, and uses those values as keys in a dictionary, the values from the second parameter are then used as values in that dictionary. I was using map(None, keyList, valueList), but zip seems cleaner.

Anyway, if you’re looking for more info on stats querying, try the BF2 Technical Info wiki, or check out SaladFork’s Guide to Creating a BF2 Stat Signature - although it’s in PHP, he does give a nice list of column names and their meanings, you can also grab lists of ranks, weapons, vehicles, etc.

Update: Also see: Battlefield Stats in PHP

Updated: Since this was written, some things changed with the stats system, and the GameSpy application requires you to pass a bunch of columns you want info for. This can help customise the data you get back, so you only request what you need. I’ve included all the columns in the info variable, which you can customise. Make sure it contains only valid columns, or you won’t get any data back at all.

As above, for info on what all the columns etc. mean, check out the BF2 Technical Wiki.

I decided it might be a good idea, from a debugging and administrative point of view, to save the reports people were viewing in my application at work. Since users are distributed all over the country, and I have to communicate with them over the phone with on-the-spot problems, it’s hard and very time consuming to get them to tell me all the parameters etc they’re using to generate a report which they are having problems with (mostly, the data looks like something they weren’t expecting).

Anyway, I thought saving the exact report they are viewing is much easier for me to simply call up while someone’s on the phone, than doing the whole ‘which options did you use?’ thing.

Option one was saving each report to a PDF file on the server, but, that’s pretty inflexible, and also, people can view more than just PDF files with my reporting options (emails can be send direct, zip files can be downloaded, and data can be downloaded in csv format), so that wouldn’t always work out.

So I looked into serializing the actual report object used to generate any of the above report types, since that object contains absolutely all data, totals, titles, info, etc.. Unfortunately, PHP’s built-in serialize() and unserialize() functions don’t work too well with complex data structures (arrays within classes, multi-dimensional arrays, etc, etc), and I couldn’t really work around all that without writing a few GBs of code onto my report class.

SO, I turned to XML. As it turns out, the PEAR ‘suite’ of scripts contains a rather useful XML serialization class -XML_Serializer, which can turn any data structure into an XML string, and for reading those strings back to usable PHP variables and objects.

It’s really quite simple:

$object = new SomeClass();
$object->var1 = "Hello World";
$object->etc();

$serializer = &new XML_Serializer(array("indent" => "  ", "typeHints" => true));
$serializer->serialize($object);
$xml = $serializer->getSerializedData();

$xml now contains the full definition of $object in XML. You can write $xml to a file, save it in a database, whatever you like.

You can then come back later, and load the file/database record/etc into a string, and deserialize it…

$unserializer = &new XML_Unserializer();
$unserializer->unserialize($xml);
$object2 = $unserializer->getUnserializedData();

echo $object2->var1;
$object2->etc();

Quite fun actually :D. You can obviously do a lot of error checking, and other things, but that’s just the basics.

Ok, so this is such an insanely simple thing to do. I once tried looking for a PHP class or package which could write Excel .xls files from data in an array. Well, I found a really ugly class which simply saved a .csv file as .xls. Anyway, I ended up writing my own 4-line function for that:

function arrayToCSV($data) {
    $csv = implode(',', array_keys($data[0])) . '\r\n';
    for ($i = 0; $i < count($data); $i++) {
        $csv .= implode(',', $data[$i]) . '\r\n';
    }
    return $csv;
}

You’ll have to do your own validation for empty arrays and things elsewhere. It returns a string with each record from the array on it’s own line, separated by commas. $data is expected in a format something like this:

$data[] = array('name' => 'Bob', 'age' => 12);
$data[] = array('name' => 'Jack', 'age' => 15);

Which looks something like this: print_r($data):

Array
(
    [0] => Array
        (
            [name] => Bob
            [age] => 12
        )
    [1] => Array
        (
            [name] => Jack
            [age] => 15
        )
)

If you’re using ADODB, you can use this little function to convert the recordset to a suitable array (there are some built-in functions to convert recordsets to arrays, but they all end up giving you pretty useless data).

function rsToArray($rs) {
    $arr = array();
    while (!$rs->EOF) {
        $arr[] = $rs->GetRowAssoc(False);
        $rs->MoveNext();
    }
    return $arr;
}

Since I’m bored at the moment, I might as well post some code :D

PHP has 2 nice functions, explode() which breaks a string into an array using a separator, and implode() which takes an array and glues it back into a single string using a separator. I use it regularly, so eventually ended up needing one for Delphi too.

I cannot take full credit for the Explode function however, I found it somewhere and can’t for the life of me remember where that might be. It is somewhat modified from the original though…

Also note that these work with TStrings, rather than arrays.

function Explode(const str: string; const separator: string): TStrings;
var
  n: integer;
  p, q, s: PChar;
  item: string;
begin
  Result := TStringList.Create;
  try
    p := PChar(str);
    s := PChar(separator);
    n := Length(separator);
    repeat
      q := StrPos(p, s);
      if q = nil then q := StrScan(p, #0);
      SetString(item, p, q - p);
      Result.Add(item);
      p := q + n;
    until q^ = #0;
  except
    item := '';
    Result.Free;
    raise;
  end;
end;
function Implode(const Strings: TStrings; const separator: string): String;
var
  i: Integer;
begin
  Result := Strings[0];
  for i := 1 to Strings.Count - 1 do
    Result := Result + separator + Strings[i];
end;

I’ve been adding some nifty things to my PHP project at work (cellphone starter pack invoicing, usage tracking [big bro is watching you earn him money every time you use your pre-paid airtime :P], etc). It’s got a lot of pretty nice features. Using client-side JavaScript, it actually pretty much behaves as a normal desktop application, only it lags like hell when you visit other pages (slow web server :P).

Anyway, I can’t claim I’ve written all the snazzy features myself unfortunately. Due to time and pressure I’ve been relying on good old Open Source to help me out. There’s actually a helluva lot of stuff out there to make things easier for just about anything you need to do…

  • ADOdb - http://adodb.sourceforge.net/

    Obviously the first thing to get going on any database-aware application, is to actually interact with the database. PHP has an Interbase module, with a whole bunch of Interbase functions. These all work fine, and there’s really no problem with them. ADOdb however makes working with SQL databases so much easier. No need to remember PHP’s randomly named module functions, and it gives you access to a huge assortment of database drivers (of corse all dependent on normal PHP modules). It’s even available for Python now!

  • Smarty - http://smarty.php.net/

    Next you’d presumably like a fancy presentation for your application. You have three options here - painfully output every single line of HTML manually through your code, create yourself a template engine/language, or use Smarty. Smarty is a Template Engine, which lets you define “.tpl” files which are bascally just HTML files with a couple of variable placeholders and smarty function calls. But it’s not just the simplicity of creating a Smarty instance, assigning variables to it, and then just calling display(), it’s the functions you can put into your template files. Looping through customer listings, building tables or drop lists, check lists, etc, etc, etc. One of the most useful things I’ve found is the ability to define your own smarty functions, allowing you to add custom functionality to your templates and the output they generate.

  • PHP pdf / PDFClass - http://ros.co.nz/pdf/

    One of the requirements of this project was that reports had to be generated in user and printer friendly PDF format. At first I looked into the option of having Smarty generate tabular reports, and get an HTML to PDF processor (there are several PHP options available) to turn my HTML into the PDFs required. Unfortunately, for the most part, these converters are heavily buggy, and didn’t give me very much control at all over the output (ok, I had full control over the output, but things like page headers and footers, page numbering, etc, etc are required for nice reports). Anyway, so I set about using PHP’s PDF functions. Unfortunately, that turned out rather risky across different versions of PHP, and was generally a pain to work with. Enter this package. It doesn’t require any of PHP’s PDF modules, so it’s free from cross-version and cross-platform bugs and stuff. It also has a bunch of nice functions for headers, footers, tables, etc. It also provides the option to save the output to disk, output direct to browser, or plop the output into memory where I can play with it. I’ve built a very nice reporting class around this package.

  • Code 3 of 9 Barcode Generator - http://www.sid6581.net/cs/php-scripts/barcode/

    Another requirement of the system is the ability to group multiple items into a single item. From the code side of things, it’s fairly simple, but to users, trying to manage these million boxes of starter packs and remembering or creating their own codes for these boxes would obviously be rather difficult. Anyway, I though it’d be nice to offer a barcode people can print and stick to the boxes. Enter this little script. Couldn’t be easier to use, and with the help of a little Javascript, users can even scale the barcodes up and down (by dynamically reloading the image, not just changing the dimensions and possibly corrupting it) before printing.

  • PHPMailer - http://phpmailer.sourceforge.net/

    I’m using this for sending my PDF reports via email. It allows you to easily attach files, or file content (so I don’t need to save the PDF’s to temp files before attaching, just attach the output directly from script). Also supports SMTP, so no need to rely on PHP’s mail configuration.

I’m also using a nifty little ZIP lib that allows me to zip my in-memory PDF reports, and send them direct to the browser for downloadable reports (since a normal PDF will open in the browser). Unfortunately there’s no readme or author URL in the source :)

I did get it from PHPClasses.org though, which has quickly become by first stop for anything I need in a hurry that I couldn’t be bothered, or don’t have time to write myself. Nice rating system and “top 10"s filter out the good stuff instantly, making finding stuff really simple. I highly recommend it to any PHP developers.

Dunno if anyone would have noticed but the site was blinking on and off last week, with dynamic DNS issues.

I’ve been using an application which runs as a service on my Windows machine, but it seems to often give up if it can’t get a new IP or the update fails, and sometimes it just doesn’t bother even trying :-).

Anyway I slapped up a quick Python script to be run from a cron job at 5 minute intervals to check a website which provides my IP (like http://checkip.dyndns.org), grab the first IP it finds, and updates my ZoneEdit account with the new IP.

Seems to have been running reliably the past few days now.

I’ve dumped it on the Files page if anyone would like to give it a go. It’s set up for ZoneEdit, but I’m sure it’s easy to adapt to other services as well.

*sigh* Look at me starting a million projects and never finishing any of them :P.

Well this one, I fully intend finishing at least. It’s a wxPython GUI front-end for Dosage (http://slipgate.za.net/dosage/) which basically has the sole goal of making managing your comics easier for the mouse potatoes out there (and makes Dosage more accessible to the average Joe user who doesn’t want to mess around with command lines and stuff).

At present, it doesn’t do much, it simply builds a nice tree of comic modules (virtual modules are displayed as branches) and allows you to add those to a list (which basically makes up your ‘subscriptions’), and lets you select one or more of those and have Dosage download the latest strip for them.

Seems I’ve spent most of today writing Dosage (http://slipgate.za.net/dosage/) modules - managed to find a whole load of comics, and ended up making 10 new modules.

It’s surprising how many comics have their main images sliced in half somewhere midway through the image (so it ends up being 2 images which Dosage obviously won’t handle), I found some that even have each panel in a separate HTML table cell :-/.

Not sure if it’s bad web design or whatever, but it’s a pity since they’ll never make their way into Dosage…

Well as expected, my little wxPython dict client is finished.

I decided to install the File Management plugin to let me put this stuff on here somehow… So check out pyDict in the “Files” link on the top-right of the site.

Or simply go here: http://shrimpworks.za.net/filemgmt/index.php

The ReadMe explains the basics of how it works and stuff…