Category: Technology

Another Small Project

Following on from the small project I showed off last night, I thought I would draw a little attention to one more little project I've been working on - my recent links. I have, for a while now, had some recent links shown in my sidebar, but the sidebar only shows the most recent 5, and they have, until now, then faced oblivion. Not any more! I have a page devoted to showing them now.

I will, at some point soon, split them into monthly and yearly archives, although there's little point in doing this whilst there's only one month of such links to archive. I will also add an RSS feed and set up a monthly, automatic post containing that month's links. Aren't you all lucky!

Well, I am now off to the wonderful event that is LUGRadio Live 2008, which I'm sure I will post about later tonight or during the week!

Writing Functions In Sassenach CMS

I am currently carrying out a little more cleaning up of the Sassenach CMS codebase, starting with themes. At the moment, Sassenach CMS themes are fairly complicated and easy to break if you don't know what all the code does. This may seem an obvious point, but the average person designing a template doesn't necessarily want to deal with the entire codebase - they just want to style their website. In order to take away most of the complicated code, I have set about writing functions that call the code from elsewhere.

This, unfortunately, took much longer than I was expecting. In fact, it took 6 hours last night just to get one function working. It was, of course, all my own fault. So, before I explain the functions, two quick tips: firstly, if your function doesn't appear to work, make sure you've called it properly. Let's say we have the following function:

function my_new_function {

}

That's fine, as long as it is declared within PHP. However, when it comes to calling the function, don't make the mistake of doing this:

my_new_function; // This will not work!

Instead, make sure you call it like this:

my_new_function(); // This will work!

Basically, I forgot to include the parentheses when calling my function. Silly. Anyway, there was a further problem which manifested itselfwhen including other external files within my function. I was trying to do this:

include $file;

This wasn't working, however. So, I tried the actual file I wanted to include on this occasion:

 include 'file.php';

No problem. As far as I was concerned, $file == 'file.php', so it should all work. I couldn't work it out. It didn't make sense. It should work - but it doesn't. I checked my PHP and MySQL book, but it didn't give me an answer. I Googled for 3 hours, with no result. I checked the PHP website, Tizag, DevShed, everywhere else I could possibly think of, but no, nothing.

I chatted to someone on the phone about it. We decided Greek made more sense. Then, one of my housemates came back. We chatted for a bit. I rambled on about the problem for a few minutes. They listened politely, but I may as well have been talking Chinese.

Then, I went back to it. It still didn't work, so I copied a snippet of code from the PHP website. It worked. I adapted it. It still worked. I didn't understand at all. And then it hit me like a concrete block. It was obvious. Talke a look:

$file = "'functions/'.$function.'php'"; // Do you see the problem here?

include $file;

I am a muppet. I had double quotes that were completely unwarranted and broke the script. No amount of Googling would come up with that answer.

So, having exposed my blatant error to the world, hopefully I have saved others from the same mistake - and we can move on to Sassenach CMS functions. I didn't want the functions to all come from the database, because that puts unnecessary load on the database. Similarly, I didn't want to include every function at the top of every script when they weren't always needed. Thus, I have written a function that is designed to call other  functions as required. Here it is:

function get_sassenach_function($function) {

$sassenach_function = 'functions/'.$function.'.php';

include $sassenach_function;

}

 Thus, if you called the function like this:

 get_sassenach_function(links);

Then Sassenach CMS would, ultimately, run the script at 'functions/links.php', which then executes the code that no-one should really need to deal with.

However, there is a chance that people may want to use their own custom functions. What happens then? There is, of course, the option to hack the scripts, but I wouldn't advise this, especially as any upgrade would likely overwrite them again. Instead, we will have a directory within which people can place their own modified scripts and run them. So, that might look like this:

function get_sassenach_user_function($function) {

$sassenach_user_function = 'functions/user/'.$function.'.php';

include $sassenach_user_function;

}

 Thus, users can define their own functions and call those without having to worry about having their custom functions overwritten. More importantly, they can call their own custom functions easily.

There is, however, one other possibility. What if a particular theme wants to call its own functions? Well, the same kind of principle applies, except that the functions would be stored in a functions directory in that themes folder, and would use another slightly different call, yet to be written, which would be get_sassenach_theme_function($function). This will need to be a little different in design as it requires knowledge of which directory the theme is found in, but it will still wirk without too much trouble.

There is one more problem to overcome - what if you need to call a function more than once? This is actually quite easy to overcome, and it is done like so:

if (!function_exists('example_function')) {

function example_function() {

// The function is defined here

}

}

example_function(); ?>

So, each time the function is called, the top of the function file checks to see whether the function has been defined before. If it has, there is a problem - that functions can only be defined once. So, if the function has already been defined, it just calls the function. Otherwise, it defines the function and then calls it.

And so there you have it, a guide to functions in Sassenach CMS. What a fun post. Does anyone still have the will to live? If so, feel free to comment. Comments should now be working - if they're not, you should let me know!

Firefox 3: Another View

Following Cheezy's review of Firefox 3, I thought I'd get in on the act. I've used Firefox for a long time and, quite frankly, there's no better browser out there. Opera is over-rated; I.E. is best ignored. Konqueror has always been very fast, but not widely compatible with all websites, is KDE-baed and has a file manager that gets in the way; Epiphany is a great GNOME-based lightweight browser, but isn't available on other platforms. Safari is a very good browser, but it takes an age to start up and doesn't use standard buttons, which is frustrating when you aren't using OSX.

Firefox. on the other hand, has always been very reliable, fast, if needing a lot of memory, compatible with most of the Internet since it started to get more widely adopted and is generally very good, with the slight drawbacks of an on-going memory leak and a tendency to crash. However, with version 3, these issues have been rectified.

The first thing I notice about Firefox 3 is that it runs incredibly fast. It starts almost instantly and is much more responsive. It looks a little different, but that's no real problem - you can alwayd theme it yourself. The new folders for your most visited links are not a great help to me, but I'm sure they are to lots of people. However, like Cheezy, the new form the address bar takes is a real disappointment. I don't want Firefox to start searching everything when I'm clearly typing in the start of an address. It makes the rest of the address impossible to find when you don't know the exact address and there are 50 other very similar addresses that Firefox has found. There should be an option to turn that off.

Other than that, Firefox 3 is very good. It's certainly more sturdy than it has been before, and its speed evokes more confidence, but that fricking address bar is incredibly frustrating.

In Praise Of Proxy Servers

To be honest, I've never really known much about proxy servers. I've never really needed them. I don't need to get around any Intrernet filters, I don't live in China and, to the best of my knowledge, don't have a great deal to hide. Thus, what's the need for a proxy server, eh?

Well, today I found a good use for one. I was transferring a website across to a new server and the nameservers were causing me hassle, making it hard for me to edit the website. The problem was, I was looking at the old website, as seen below:

The old BUSY website

There's even a nice wee message to tell you it's the wrong one! But that's done me no good, of course, so I needed to take some action. I had a few options:

  1. Wait. Not my strongpoint;
  2. Try to access through an I.P. address. This is probably not possible;
  3. Guess that what I'm doing will work. This is always a bad assumption;
  4. Set up the website on my local server. Unfortunately, this would take a while;
  5. Use a proxy server. It was the quickest option and clearly worth a try.

It's not something that was guaranteed to work, but it did, as you can see from the picture below:

The BUSY website through a proxy

Obviously, the advert was added by the proxy server - they need to make money somehow, I guess. I was then able to edit to my heart's content. See, proxy servers can serve legitimate purposes!

Progress Is Good

Although I've done little on my little project today, I have spent three whole days working on it this week, rather than spending my time on my dissertation like I probably should have. Still, I managed a few significant things yesterday, so I thought I'd provide another short update.

My nice to-do list can now be updated without a problem, which has helped me keep track of things nicely. I was very excited on Tuesday to find the first two bugs in the code I'd written: there were two scripts which used the $_GET() function, and were meant to perform certain actions like delete things from the database when given certain variables in the url. I had, however, mistakenly allowed the script to delete as long as something was appended to the url, regardless of what this command was. Here's an example:

http://www.noelinho.org

That's the web address.

?action=delete&post=21

Those are the variables. When put together, we get this:

http://www.noelinho.org?action=delete&post=21

Assuming the action "delete" does what it says on the tin (and it does), then it will look in the database for post 21, and delete it. Unfortunately, my carelessness meant that it would have done the same if action was equal to "create", "modify", or even "" (blank). Still, it's on my to-do list to be fixed...

However, I have, much more excitedly, managed to implement that two things I thought would be hardest: RSS feeds and nice permalinks, using mod_rewrite. The RSS feeds were quite simple once I'd realised that certain html entities break XML, and then used the necessary PHP function to strip them from strings. It probably needs a little more work, but it's functional at the very least right now. I was even more satisfied to get mod_rewrite working. For some reason, I couldn't get it to work on my local server, but once I'd uploaded the scripts to this website, I managed to get them working. Thus, I can now start with an address such as:

http://www.noelinho.org?year=2008&month=01&title=noels-first-attempt

And I end up with:

http://www.noelinho.org/alpha/2008/01/noels-first-attempt/

Awesome! mod_rewrite is brilliant... but complicated. Like, nigh-on impossible. But not quite.

Another Noelinho CMS Update

I've been continuing to use whatever time I can to work on my little CMS project which I have mentioned before. Just over a month has passed since then, and I have managed to progress a little further, especially in the last week. Given that a few people have asked about it recently, I thought I'd post a little update.

I'm still only working on the back-end of the system at the moment - the front-end can be sorted out afterwards. The basic structure of thre back-end has remained the same, but I've decided to split many of the pages in the different sections into two or three pages. The idea of this is to make the whole thing easier for people to understand, and to make each page a master of its domain, so to speak, rather than to make it a lengthy complexion of 'if' statements for five different tasks. It makes working out bugs much easier too!

One significant change is in the way 'categories' are stored on the system. They were stored in a set' field on the 'posts' table, but I've now created a 'categories' table, and each category is a row on that table. It enables categories to have parent categories, but also means I can have one table for both link and post categories. There are problems with creating arrays from this at the moment, so I've decided I'll come back to it another time. I have kept my previous 'set' system just in case it doesn't work in the end, but I was more disappointed that I no longer had a use for my wonderful explode() code, which I did rather enjoy...

I have managed to adapt TinyMCE to fit better in the back-end now, but also to use a more complicated theme that didn't previously work. It still needs a little tweaking, but it would probably work fine just as it is at the moment.

Many of the other things I mentioned in my previous post have not yet been worked on, but there are other things which have progressed. Submitting new links now works well, as does submitting new categories for links, and distinguishing between post and link categories. Parent categories do not yet work, since that option hasn't yet been fully added to the database. The forms have all been nicely styled now too, making them both easier on the eye and clearer to use, as you can see from the image.

I haven't written any documentation yet (I expect this will be done last), but I have transferred my nice 'to-do' task list to the database. I originally developed this so that I could keep track of what I needed to be doing, but then realised it would actually be very useful for other people to keep track of all the things they wanted to do if they were using it too. Thus, the 'to-do' tab probably shows the most complete part of the software at the moment. It is split into three sections: 'implemented', 'in progress' and 'not yet started', with a form at the bottom for submitting tasks. In time, functionality will be added to alter task status and to delete tasks - but only completed ones. To delete uncompleted tasks, one will have to change their status to 'implemented', then delete them, so they can't delete them by mistake.

Making An Autorun CD/DVD

I grant you, most people have little reason to read this post. However, one day, some person will visit this post looking to do precisely what this post talks about! If you're just wanting to read about the autorun part of the post, it is explained towards the bottom - the first half of the post talks about the rest of the CD/DVD!

As part of the technical work that I do for the Baptist Union of Scotland Youth, I have, for the last two years, produced a mission review CD (last year) or DVD (this year) which is mainly full of photographs from missions, with a few other bits thrown in. The CD or DVD is based around an HTML browser through which you - guess what - browse through all the photos from the missions. Other bits thrown in might be a couple of small videos, an evaluation form, contact details, website links, etc... It's generally easier if you can make the CD/DVD run automatically since you then don't have to worry about making sure people know which files to run, etc... (although if they have disabled autorun, then you do, but it's their problem if they've done that). Anyway, my methodology for making the CD/DVD goes as follows:

This provides me with the base that I need to put everything together. However, there is then the small matter of one HTML file for each standard size picture. The DVD this year had 2,701 photographs on it, and I'm sure not going to write 2,701 HTML files to go with them! Thus, I need a script that does it for me. In steps galrey, a Linux command-line program. All I do is fill in a few variables and set it off to create all the files for me, and an index.html file for each folder. It does require some fiddling: as with most command-line programs I know, its HTML is pretty shoddy, but it does the scripting fantastically well. Having altered the HTML, cleaning it up and applying my template, all is fine and dandy. I am then left to add my extra pages manually and to put in an index.html file for the disk as a whole. Easy. At this point, I usually spot a mistake in my navigation bar and realise I need to repeat this step of the process, but never mind!

Thus, the CD/DVD is pretty much complete. The one bit left to do is to make the CD/DVD run automatically. I should, at this point, make two quick points. Firstly, it doesn't matter whether the medium is a CD, DVD, or even a USB storage device, the autorun method is the same - although all three require a PC which is set up to automatically run the medium if autorun is detected. Secondly, I'm not going to talk about Macs. I don't provide autorun support to Macs. It's just too much effort. Well, okay, so it's also to do with the fact that I don't have a Mac to test on, so I couldn't guarantee it would work!

Making the DVD run automatically on Windows and Linux is done separately. It's meant to be easiest to do on Windows, but I've found it easiest on Linux, partly because of a script I found as part of another autorun guide. Thus, I'll talk about autorun on Linux first.

Autorun on Linux

If you take a look at the script, which looks to execute an index.html file, you'll see it's a simple bash script, designed to look for a web browser through which it can execute the file index.html. Very simple really. Except, I found it didn't work. Thus, I set about modifying it. The first problem was that, when I ran the script from inside an existing terminal window, the terminal claimed no browser was available to execute index.html. This seemed a little odd, since I have Firefox installed, and the script includes both Mozilla and Netscape. However, a quick look at my system showed that Firefox is executed through the "firefox" command, so I added this to the script. (Firefox is launched through one of a few different commands depending upon a linux system: sometimes by the command "firefox", sometimes "mozilla-firefox", and occasionally by use of the command "mozilla". Confusing!)

The second problem I found was that when Firefox opened, I simply a tab which showed my homepage and a tab showing some folder on my Linux install. Not very helpful if you don't know where to find index.html! However, a closer inspection of the script explained to me why this was.

The script tries to set the first tab through autorun.inf (which I actually use to autorun for Windows, but I'll go into that later), but doesn't succeed, because autorun.inf doesn't contain this information! Therefore, it has ended up showing a directory it shouldn't be showing (I can't remember what it was, but the point is, it wasn't what I wanted, therefore it didn't work!).

A rush of common sense overtook my brain for a split second, and I decided that there was actually no point in processing anything through autorun.inf at all, when I could just specify index.html instead of autorun.inf. I also realised, however, that there was a problem in specifying "$BROWSER /media/cdrom", since /media/cdrom is completely pointless on my system - my two CD/DVD drives are /media/cdrom0 and /media/crdom1. Thus, it will never find the right folder. The solution? Easy, take out the absolute link and replace it with a relative one - index.html. Since we're already in the folder with the index.html file, there's little point in searching for it - we already know where it is!

Curiously, however, there is still the second tab, which shows the homepage. This is shown because the very bottom of the script tells the browser to open it. Since I'm not personally wanting anyone to look at their homepage (they can open it themselves if they want), I just deleted this part of the script. Now, the script works wonderfully on my Linux system. When I place the DVD in my drive, a pop-up alerts me that it has detected autorun, would I like to enable it? I click "confirm", to confirm that I am expecting it and it's not going to eat my computer, and it opens index.html in all its glory. Fantastic. If you want to see my modified script, you can. To use the script, rename it "autorun" (with no file extension!) and place it in what will be your CD/DVD/USB's root directory.

I should say that I suspect the bottom part of my script is unnecessarily bloated. At the bottom, my modified script reads:

HOMEPAGE=`grep homepage index.html | awk 'BEGIN {FS="="} {print $2}'`

if [ ! -f "$HOMEPAGE" ]; then

$BROWSER index.html &

fi

exit 0

It would probably work reading just:

$BROWSER index.html &

exit 0

However, I've not actually tried this to make sure. If it works, great. If it doesn't, just use it as it appears in the text file. So anyway, that was autorun on Linux.

Autorun on Windows

Autorun on Windows - supposedly easier, though not for me. The problem is that there are so many different ways of doing it. The way I've done it is by writing an autorun.inf file with this inside it:

[autorun]

shellexecute=index.html

shell=index.html

icon=favcon.ico

In theory, this should work. In practice, I've found it to work some of the time, but not all of the time. However, when it doesn't work, Windows Explorer seems to come up anyway, so as long as the user thinks to click on the index.html file, then they're fine.

However, ideally we need a workaround. There are plenty of programs out there that will do the job for you, but most are closed source, proprietary solutions. I want an open source solution. And I've found it. "What is it?", I hear you ask. Well, I'll tell you, as long as you promise to keep quiet about it. It's Firefox Portable. You see, Firefox Portable is set up to work from USB keys, using a relative path, and so it immediately gets around the problem of which browser to use. You simply include the browser on the CD, DVD or USB key and specify the autorun.inf file to launch, via a relative path, the executable file on startup. Thus, all you have to do is write the autorun.inf file. Easy!

Well, actually, that's not quite all. You see, if you do that, and burn it all to a CD or DVD, you'll run into a problem. The problem is that Firefox is not able to run from read-only media. The trouble is, that's exactly what we're trying to do! Well, there is a way around it. First, we must run FirefoxPortable so that the application creates all the files it needs in order to operate. Then, we need to go to the FirefoxPortable/Other/Source/ directory and copy the FirefoxPortable.ini file to the main FirefoxPortable directory.

This file is our friend. We want to open and edit the file, in a normal text editor. The crucial line in the file is the last line, where it says "RunLocally=false". We want to change this value to false, which forces Firefox to run in the RAM, and so means that it doesn't try to save anything to the hard drive, which is what caused our errors.

Next, we want to set the homepage for our users, using a relative path, specified half-way down the file in "LocalHomepage". This is most likely to be "../index.html", or similar (without the quotation marks - they're for your benefit). Once this is done, make sure you launch the browser to make sure it does what you want it to.

Please note, if you then want to make a change, you must change "RunLocally" back to "false", or your changes will not work. You can, if I remember correctly, install themes as you wish, and add-ons too, as long as they don't require writes to the CD, DVD or USB stick when used by the end-user. However, you cannot use relative bookmarks. I've tried this without success. Bookmarks require absolute paths, it would seem. You should probably attach a note to say that the attached browser should not be used for general Internet use. This is because you are not able to install security patches, and so computer security could be compromised. The risk is not a great one, but a cautionary note won't harm.

The autorun.inf file would read as follows:

[Autorun]

Open=FirefoxPortable\FirefoxPortable.exe

Action=Open BUSY Photo DVD 2007

Label=BUSY Photo DVD 2007

Icon=favicon.ico

Now that all this is done, you are ready to burn your media! Just make sure you didn't make a mistake...

I hope this tutorial has been helpful. I certainly had fun trying everything out, and it was a great help to be able to get around browser compatibility issues (well, Internet Explorer issues!) by simply distributing a browser with my work. Kudos especially to John Haller on that one.

I Am An Idiot

I did something very silly today. I was working on my CMS Project today, but having problems. I was working away at a form for adding categories via the back-end of the system, but wasn't getting very far. The categories live in a SET column, which can take up to 64 variables, any number of which can be used for a particular post. If none are ticked, the post goes to a 'General' category. Anyway, updating a SET field takes some doing, so to edit it I need to go through the following process:

Nice and easy. The trouble was, it didn't do anything. It worked perfectly in phpMyAdmin, but not on my self-written script. I couldn't understand it. The code was perfect - I used echo() on my browser to make sure it was. I made sure all the slashes were correct. I used stripslahes(), addslashes(), and almost resorted to slashwrists(). But then it hit me.

I hadn't actually run the query on the database. I'd written all the PHP code to deal with the results the query would show up, but I hadn't actually run the query.

What a muppet I am. Please don't make the same mistake as me.

IMAP On Gmail

I've had a Gmail account for over three years now, and whilst Gmail is fantastic, especially in giving me about 6 Gigabytes of storage, one thing I've wished for a long time is that they would add support for IMAP. I used to use POP to access Gmail, it was frustrating when using multiple computers.

Well, I was fumbling around in my settings page today when I noticed that, since November, IMAP has been enabled on Gmail. That makes me happy!

I do, as an aside, also notice you can now use Google Apps on your website. One of the advantages of this is having a Gmail account with your website address in it, but with all the perks of Google's storage space. Handy, when you're strapped for storage space on your web hosting.

Noelinho CMS Update

I've been doing a little work on the Content Management System (CMS) I'm writing over the past couple of months, so I thought I should give a little update. I've made good progress this time, especially having solved my password troubles. Authentication has always been the stumbling block I've had in the past, but now that is successfully implemented, it's all dandy.

The main thing I've been looking to do is implement an inline text editor. I'm using TinyMCE, which is what a standard WordPress install uses. It's quite nice, although I've not managed to make it look the way I want it to, or add the features that I want in there, because I don't understand Javascript. I need to get my head around that, which may take a while. Javascript is a really stupid language if you ask me. I just don't get it - but then again, people say that about PHP too...

Anyway, TinyMCE is used to format posts, and I have managed to get it to write to the database, so it does work - I just need to make it fit better. Once items are in the database, they can be managed through PHP's $_GET system. I'm sure there's a newer, supposedly better way of doing this, but I've not come across it yet, so it'll stay like that for now. It's simple enough. I need to write a nice little help section too - something sadly left out of many systems. Why make people go to a forum if you can answer all the questions on the back-end of the system? I'm also in two minds on the options system to use: on the one hand, lots of people find it easier to hold certain options in the database. This is how WordPress works, but it's simpler to just hold them all in a file, and I prefer it that way too. It makes for quicker loading, too. One compromise could be to use a file that's written to from the database, but maybe that's just a waste of time...

I have, very helpfully, built in my own small to-do list on the back-end. This could, as the whole thing develops, be left as a little notes page for administrators to store thoughts and the like, but for now, it stores the things I need to take this project further forward: nice URLs and RSS feeds (nasty, both of them!), categories, pluggable themes and the all-important search facility. Hopefully I'll get some solid progress on this over the coming months, as there are a few people interested in using this if it turns out nicely, which it will!