31 Dec


I’ve the most awful memory.

While trying to remember what the hell I’d done in the last year, I came up with nothing.

Luckily, I have a spare brain in the form of my facebook friends, who came up with this list for me:

  • I started a new company, KV Sites, which will be up and running properly within a month or so, and will be selling affordable CMS websites and programming.
  • I got grade 2 in piano. I’m still waiting for an examiner for grade 3 (which I wanted to do in September). I’ll be doing grade 4 in March.
  • I got my first grading in Genbukan Ninjutsu.
  • I finished another book, CMS Design using PHP and jQuery. I hope it is as well-received as the previous book, jQuery 1.3 with PHP. btw, Packt would like me to remind people that the book “Mastering phpMyAdmin […] for effective mysql management” (reviewed here and here) has been updated to version 3.3.x.
  • I am building up to a new release of my CMS, WebME, which, despite the last downloadable version being from early 2009, has actually been very actively updated. It should be ready for release tomorrow, right on time for 2011!
  • I wrote and released two jQuery plugins: k3dCarousel, and SaorFM (which I hope to vastly improve in 2011).
  • I also built a first attempt at a clavichord made from plywood. I’ve got some new tuning pegs and redesigned the keyboard, so will hopefully be able to record on it soon.

I’m hoping 2011 turns out to be awesomer and that my head will be able to remember it all!

26 Sep

SaorFM progress – the Hidden Files plugin

In the last post, I mentioned that a jQuery plugin had been created.

At the time, it could only be used as a file or directory selector.

It can now also be used to upload, download, and delete files.

I’ve also enhanced the core engine so that it now has plugin support.

The first plugin is a Hidden Files plugin, which lets you hide files or directories depending on their names. The default pattern is to hide nodes with names that begin with a ‘.’ – this is the default for most systems out there.

I’ll explain how plugins work, in the hope that someone out there may be interested in creating one 😉

For this example, I’ll use the Hidden Files plugin, as it’s already created, and uses everything in the engine so far.

First off, you create a directory in the /plugins/ directory of the plugin. In this case, I created the directory /plugins/hidden-files/.

In that, the only essential file is config.php, which holds a configuration for the plugin:


When you tell SaorFM to install the plugin (using $SaorFM->installPlugin('hidden-files');), it will read through that array and add the details to its own configuration file, so it doesn’t have to open up multiple files every time it boots up.

As an example, here’s my test config before the plugin is installed:


And here’s how it appears after the installation of the plugin:


There are three additions:

  • "plugins":["hidden-files"] – this is an array of installed plugins.
  • "triggers":{"checkfilename":["HiddenFiles_checkFilename"]} – the $config array above had a trigger mentioned – that’s converted into an object and added to the SaorFM config.
  • "hiddenfiles":"#^\/?\\.#" – this is to tell the hidden files plugin what pattern to apply to file names to decide whether they should be hidden or not.

The first two are obvious – the first is the name of the plugin, and the second is the name of a trigger named in the config array.

For the third, we need to run an installation script when Hidden Files is installed, so SaorFM checks the /plugins/hidden-files/ directory to see if a file exists named install.php:

if (!isset($this->_config->hiddenfiles)) {
  // the default pattern hides files that begin with .

That’s run by SaorFM when the plugin is installed. It adds a default hiddenfiles value to the config. This can be changed at any time afterwards.

Ok – so we have the config installed – now how does it work?

Let’s say we ask SaorFM to list the files in ‘/’: $SaorFM->listFiles('/');

Inside the listFiles method, there is a loop which adds filenames to an array. For each one of the filenames, we check it before adding to the array:

    foreach ($files as $f) {
      if ($f->isDot()) {
      if ($this->trigger('checkfilename', $f->getFilename())) {
        $f->isDir()?1:0 // record as 1 or 0 to save http traffic

Notice the $this->trigger('checkfilename', $f->getFilename()) – if that returns anything other than false, then the file is not added to the list.

The trigger method cycles through any functions which have been named for that trigger, and calls each one in turn. If any return a result other than false, the method returns that result immediately:

  public function trigger($trigger, $vals) {
    if (!isset($this->_config->triggers->{$trigger})) {
      return false;
    foreach ($this->_config->triggers->{$trigger} as $function) {
      $ret=$function($this, $vals);
      // if the trigger gives any response other than false, then return it
      if ($ret) {
        return $ret;
    return false;

Note that we haven’t yet defined the function HiddenFiles_checkFilename.

Upon installation, we also load up the file /plugins/hidden-files/functions.php if it exists, and this file is loaded every time that SaorFM is instantiated after installation as well:

function HiddenFiles_checkFilename(&$saorfm, &$filename) {
  return preg_match($saorfm->get('hiddenfiles'), $filename);

This is a very very simple function – it could get a lot more complex in other plugins. For example, an Authentication plugin would be much more verbose.

I hope this is all very clear. It’s very very simple to add arbitrary triggers to SaorFM, so if you want to write a plugin and the trigger doesn’t exist, just tell me and I’ll put it in place.

After all this, let’s say you want to uninstall the plugin.

Within SaorFM, you just call $SaorFM->uninstallPlugin('hidden-files');.

This automatically removes the ‘hidden-files’ value from the plugins array (and removes that array if it’s empty), then removes any added filters as well.

Finally, it also checks to see if /plugins/hidden-files/uninstall.php exists and runs that if so:


After this, the SaorFM config file is back to the exact state it was in before we installed the plugin. Clean.

If you’re interested in hacking on SaorFM, please download a copy from SVN here.

There are a number of things we need to create before it’s usable by the general public. An installer, for example, and some widgets for popular RTEs like CKeditor or TinyMCE. If you feel you’d like to create those, please contact me.

12 Sep

saorfm: first visible results

The first visible project using SaorFM is a jQuery file-selection widget:


Here is the source of that page:

		<p>Select a file</p>
		<input id="file-select" />

		<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" type="text/css" />
		<link rel="stylesheet" href="/saorfm/jquery-widgets/jquery.saorfm/jquery.saorfm.css" type="text/css" />

		<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
		<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.js"></script>
		<script src="/saorfm/jquery-widgets/jquery.saorfm/jquery.saorfm.js"></script>

In the above demo, we link in the jQuery and jQuery-UI scripts, and load up the widget’s script.

The only content elements are a <p> telling the user to choose a file, and a normal text <input> box which the user can use as a combobox.

The magic happens with this little bit of JavaScript:


That tells jQuery to convert the #file-select input box into a saorfm widget. The only parameter in this demo is rpc, which tells the widget where the SaorFM server is to be found online.

To install this on your own server, all you need to do is download the SaorFM engine from Google Code, and add a config.php file to the core directory. Here’s mine:


In that, a JSON-encoded hash object contains the configuration. Change the user_files_directory parameter to your own files directory, and you are done with the configuration!

I’ll be adding this to my WebME project next week, after I’ve finished writing the tests (Selenium and PHPUnit).

28 Aug

SaorFM, first few commits

Last Sunday, I announced that Conor and myself were starting a new file manager called SaorFM.

We started out slow, because we want to have absolutely everything in this to be checked by PHPUnit (for console-style testing) or Selenium (for GUI testing).

We’ve got enough written that you can do the following:

  • Write and save a config file.
  • Rename/Move files.
  • Delete files/directories.
  • List the contents of a directory.

All of the above have automated tests, so we’re fairly sure they’re correct. The main class’s source is readable here, and the test’s source is readable here.

Conor is currently adding support for SaorFM into his own CMS, Furasta. I’ll be working on adding it to my own tomorrow (got relatives coming over today – busy busy!).

We need to add some more functionality to make this basically complete:

  • Move directories.
  • Upload files.

After that, things get interesting, as we’ll be adding a plugin architecture.

Tomorrow, I’ll be finishing up the basics, and will write some simple jQuery plugins to select files, select directories, upload files, etc.

Soon, we’ll be catching up on KFM in functionality ;-).

22 Aug


Last night, I spent four hours chatting with Conor MacAoidh.

We’re both the authors of CMSes, and both need file managers.

I’m the original creator of KFM, but recently, I’ve been getting annoyed at it. The project has grown too large to be easily managed, and it’s slow to start up because of the amount of database configuration involved.

We discussed this, and came up with a plan, which coincides with what I wanted to do for KFM2, but is probably much better.

We are going to reboot the whole thing – write a complete new file manager from scratch. It will only use code from the original KFM2 if the code is demonstrably better than any alternative we come up with.

The project will be properly documented, will have 100% test coverage, and will be completely free.

It will come in a number of separate parts, but only one, the core, will be absolutely needed.

The core of the engine is the bit which handles the actual file management. It will be designed to load in only two or three files for the most part, and as fast as possible.

Communication with the core will be done by either including the core as part of your own CMS, or by interacting with it via RPC.

The RPC will be very important – you send a command such as /rpc.php?action=move&from=/my-files/test1.jpg&to=/images/me.jpg, and results will be returned as JSON.

We decided on the name SaorFM. While this may be slightly confusing for non-Irish-speakers (“Saor”, pronounced half-way between “sair” and “seer”, means “Free”), we feel this is not very important. After all, Ubuntu is a household name, and that’s Bantu.

The main site will be SaorFM.org, the blog will be here, and downloads, issue tracker and SVN can be found here.

We’re still deciding on how to go about things, so there are no downloads yet. The decision to do this was made literally last night.

Having a co-developer on board from the absolute start will encourage me to get my arse in gear on this – if Conor does something cool, I have to beat that. And vice-versa, hopefully!

I’m starting the project off at the moment by working on a description of what it’s all about, and then will start writing some starter tests. This will use “test-driven development”, so every single line of code in this project will be repeatedly tested throughout the development.

We’re planning a load of features, such as desktop-/system- integration for Linux, Mac and Windows, and having totally external UI systems. We even considered going mad and creating a bump-top-like UI for it.

It’s taken me almost a year since planning KFM2 and getting to this.

Part of the reason for the delay is that this is so far removed from the current KFM, that I really didn’t know how to bring KFM1 up to the specification I wanted to reach.

Starting from absolute scratch with a brand new name is the right thing to do, I think.