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:

<?php
$config=array(
  'triggers'=>array(
    'checkfilename'=>'HiddenFiles_checkFilename'
  )
);

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:

<?php
$SaorFM_config='{"user_files_directory":"\/home\/kae\/websites\/saorfm\/trunk\/tests\/\/userfiles"}';

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

<?php
$SaorFM_config='{"user_files_directory":"\/home\/kae\/websites\/saorfm\/trunk\/tests\/\/userfiles","plugins":["hidden-files"],"hiddenfiles":"#^\/?\\.#","triggers":{"checkfilename":["HiddenFiles_checkFilename"]}}';

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:

<?php
if (!isset($this->_config->hiddenfiles)) {
  // the default pattern hides files that begin with .
  $this->_config->hiddenfiles='#^/?\.#';
}

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()) {
        continue;
      }
      if ($this->trigger('checkfilename', $f->getFilename())) {
        continue;
      }
      $arr[$f->getFilename()]=array(
        $f->getFilename(),
        $f->getSize(),
        $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:

<?php
unset($this->_config->hiddenfiles);

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:


demo

Here is the source of that page:

<html>
	<head>
	</head>
	<body>
		<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>
		<script>
			$(function(){
				$('#file-select').saorfm({
					"rpc":"/saorfm/core/rpc.php"
				});
			});
		</script>
	</body>
</html>

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:

$(function(){
	$('#file-select').saorfm({
		"rpc":"/saorfm/core/rpc.php"
	});
});

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:

<?php
$SaorFM_config='{"user_files_directory":"\/home\/verens\/domains\/demo.verens.com\/saorfm","language":"en","json_errors":false}';

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).