Tuesday, April 1st, 2008

Openbox Logout, Reboot & Shutdown Script

I have been using the latest Openbox release [3.4.7-pre2] for the last few weeks and so far I have been impressed. One of the new features from the latest release is a GDM control script. The script basically allows for a user to send reboot and shutdown signals to GDM from within the Openbox environment. This provides a means to reboot/shutdown an Openbox system in a clean and efficient manner.

Screenshot of Openbox logout, reboot, shutdown script.

I have written the following PyGTK script to take advantage of the new GDM control. Python is not currently a language that I am too familiar with, so please feel free to rip the script to bits improve as you see fit.

#!/usr/bin/env python

import pygtk
pygtk.require('2.0')
import gtk
import os

class DoTheLogOut:

    # Cancel/exit
    def delete_event(self, widget, event, data=None):
        gtk.main_quit()
        return False

    # Logout
    def logout(self, widget):
        os.system("openbox --exit")

    # Reboot
    def reboot(self, widget):
        os.system("gdm-control --reboot && openbox --exit")

    # Shutdown
    def shutdown(self, widget):
        os.system("gdm-control --shutdown && openbox --exit")

    def __init__(self):
        # Create a new window
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_title("Exit? Choose an option:")
        self.window.set_resizable(False)
        self.window.set_position(1)
        self.window.connect("delete_event", self.delete_event)
        self.window.set_border_width(20)

        # Create a box to pack widgets into
        self.box1 = gtk.HBox(False, 0)
        self.window.add(self.box1)

        # Create cancel button
        self.button1 = gtk.Button("Cancel")
        self.button1.set_border_width(10)
        self.button1.connect("clicked", self.delete_event, "Changed me mind :)")
        self.box1.pack_start(self.button1, True, True, 0)
        self.button1.show()

        # Create logout button
        self.button2 = gtk.Button("Log out")
        self.button2.set_border_width(10)
        self.button2.connect("clicked", self.logout)
        self.box1.pack_start(self.button2, True, True, 0)
        self.button2.show()

        # Create reboot button
        self.button3 = gtk.Button("Reboot")
        self.button3.set_border_width(10)
        self.button3.connect("clicked", self.reboot)
        self.box1.pack_start(self.button3, True, True, 0)
        self.button3.show()

        # Create shutdown button
        self.button4 = gtk.Button("Shutdown")
        self.button4.set_border_width(10)
        self.button4.connect("clicked", self.shutdown)
        self.box1.pack_start(self.button4, True, True, 0)
        self.button4.show()

        self.box1.show()
        self.window.show()

def main():
    gtk.main()

if __name__ == "__main__":
    gogogo = DoTheLogOut()
    main()

Wednesday, February 20th, 2008

TwitterZoid PHP Script

It's a rather silly name, I know; however, TwitterZoid is the chosen name of my PHP script for parsing Twitter RSS feeds. I've been using Twitter quite steadily for a couple of weeks now and I thought it might be nice to include my latest tweets on my blog, so I wrote TwitterZoid to do just that.

TwitterZoid differs to other PHP based Twitter RSS parsers, at least the ones I tried before I wrote it, in that it will automatically link both lexicons and URLs found within individual tweets. It also tries to mimic Twitter's timestamping, although this could be improved.

TwitterZoid usage

I wanted to make TwitterZoid as simple to use as possible. Therefore I decided to write the script to be used as a simple include file which can be used on any PHP page. Basically, to use TwitterZoid all you need to do is set a couple of variables, include twitterzoid.php and then echo the main $TwitterZoid variable where you would like your list of tweets to appear.

Example set-up:

$twitter_username = "corenominal";
$twitter_feed = "http://twitter.com/statuses/user_timeline/99713.rss";
require_once('twitterzoid.php');

Call on the main TwitterZoid variable to produce the list of tweets:

echo $TwitterZoid;

Don't worry if this reads like gibberish, I've included an example page within the download.

TwitterZoid examples

There are currently two demonstrations of TwitterZoid in action, see:

My official "What am I doing?" Twitter page:
http://crunchbang.org/what-am-i-doing/

A more stylised version of "What am I doing?", included within the download:
http://crunchbang.org/projects/twitterzoid/demo/

Download TwitterZoid

Location: http://crunchbang.org/projects/twitterzoid/twitterzoid-0.1.tar.gz
MD5: 99dace9f9872cf1ebf93588bb2d36458

TwitterZoid license

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

http://www.gnu.org/licenses/


Sunday, February 17th, 2008

Wicked Cool Shell Scripts

I've not read the book, but the Wicked Cool Shell Scripts site and its example shell scripts are, erm, wicked cool. The site offers a whole host of scripts, some of which could quite easily be adapted/hacked into useful tools. If you're remotely interested in Shell scripting, you should take a look, even people with scripting experience might learn a thing or two.

URL: http://www.intuitive.com/wicked/index.shtml

Download the script library: wicked-cool-shell-scripts.tgz


Tuesday, January 29th, 2008

PHP Function: Word Filter

So, last night I was mainly experimenting with Whird, more specifically I was trying to build an internal search feature. This is something I've been putting off for long enough, and I'd really like to get it coded up. I didn't finish it last night, but at least I've made a start.

Anyhow, during my experimentation I wrote this little PHP function for filtering words out of a string. Basically the function takes 2 strings as arguments before filtering words out of the first string based on words found in the second. I've posted it below for future reference:

function word_filter($string1,$string2){
    $string1 = trim($string1);
    $string1 = preg_replace('/s+/', ' ', $string1);
    $string1 = explode(" ",$string1);
    $wordcount = count($string1);
    $i = 0;
    while ($i < $wordcount) {
        $string = $string1[$i];
        if (strstr(strtolower($string2),strtolower($string))) {
            $string1[$i] = "";
        }
    $i++;
    }
$string1 = implode(" ",$string1);        
return($string1);
}

Example usage

This is probably not the best example, but this:

$poem = <<<EOD
<p><em>GIVE me women, wine, and snuff <br />
Untill I cry out "hold, enough!" <br />
You may do so sans objection <br />
Till the day of resurrection: <br />
For, bless my beard, they aye shall be <br />
My beloved Trinity.</em></p>
EOD;

$common_words = 'and be but do for is it may me my not of the they there so was you';

echo word_filter($poem,$common_words);

Would output something like this:

GIVE women, wine, snuff
Untill cry out "hold, enough!"
sans objection
Till day resurrection:
For, bless beard, aye shall
beloved Trinity.

John Keats would be proud, not! Please feel free to optimise, or let me know if a one line equivalent already exists :)

Tagged with: code, php, projects, whird | Comments [4]


Sunday, November 18th, 2007

Bash Script: MySQL Backup

I thought that it might be a good idea to start posting a few of my scripts; it'll be handy to have them on my site for future reference. Also, I learn a lot by reading example scripts — I guess others might be able to learn from mine.

I wrote the following Bash script to perform a backup of a remote MySQL database. The script first connects via SSH and performs a MySQL dump, saving the results to file. It then connects via SFTP and downloads the file. Once the file has been downloaded, it restores the database to my local MySQL server.

It is quite a simple Bash script and it should be fairly straightforward to follow.

#!/bin/sh
# Settings
#############################
REMOTEHOST="example.com"
REMOTEBACKUPDIR="backup/sql"
SQLHOST="localhost"
SQLDB="database_name"
SQLUSER="username"
SQLPASS="password"
SQLFILE="database_name.sql"
LOCALBACKUPDIR="backup/sql"
#############################
# Start main
echo "* Connecting via SSH..."
ssh $REMOTEHOST <<**
echo "* Performing SQL dump..."
if [ -d $REMOTEBACKUPDIR ]; then
    cd $REMOTEBACKUPDIR
else
    mkdir $REMOTEBACKUPDIR
    cd $REMOTEBACKUPDIR
fi
mysqldump -h $SQLHOST --user="$SQLUSER" --password="$SQLPASS" $SQLDB > $SQLFILE
echo "* Closing SSH connection..."
exit
**
cd ~
if [ -d $LOCALBACKUPDIR ]; then
    cd $LOCALBACKUPDIR
else
    mkdir $LOCALBACKUPDIR
    cd $LOCALBACKUPDIR
fi
echo "* Connecting via SFTP..."
sftp $REMOTEHOST <<**
cd $REMOTEBACKUPDIR
get $SQLFILE
exit
**
echo "* Restoring SQL dump to local server..."
mysql --user "$SQLUSER" --password="$SQLPASS" $SQLDB < $SQLFILE
echo "* SQL backup complete."
cd ~
exit 0

Notes

  1. For automation purposes, this script assumes that SSH and SFTP have been configured for automatic login. See "Creating Private/Public SSH Keys"
  2. It also assumes there is a mirrored MySQL server and user account running on the local machine.
  3. The script can be automated using Crontab.
  4. Lacks any error handling and/or logging!?
  5. I've worked with some commercial hosting providers who do not grant table locking privileges to their MySQL users — table locking can be bypassed by adding the "--skip-lock-tables" option to the "mysqldump" command. Use with caution.

Sunday, November 4th, 2007

Ternary Operator in PHP

Over on Planet PHP there's a running debate [see here, here & here] over the use of the ternary operator. I love a good debate so I thought I'd chip in with my 2 pennies.

The ternary operator looks attractive and can reduce the amount of code that you write. I know this but I still don't use it. I think PHP is an awesome language and a major contributing factor to its awesomeness is its simplicity. It's a relatively easy language to learn and I think that the wide spread use of the ternary operator would only increase the barrier to entry [not a good thing!]

Also, I find it interesting that the ternary operator is hardly ever referenced in the comments and code examples at PHP.net. Indeed chapter 16 "Control Structures" of the manual hardly mentions it at all.

Ternary operator code example

In case you've no idea what this post is about.

Before: no ternary operator, easy to understand

if ($treat == 'cream') {
    $cat = 'Happy!';
} else {
    $cat = 'Not so happy.';
}

After: ternary operator in use, less code but not so easy to understand

$cat = ($treat == 'cream') ? 'Happy!' : 'Not so happy.';

Tagged with: code, php, programming | Comments [1]


Friday, November 2nd, 2007

Image Hotlinking Prevention with .htaccess

I'm designing some banners and buttons for Ubuntu advocacy. I have no problem with giving the images away [indeed this is why I made them,] however I really can't afford to host them. So before I post them to this site I wanted to ensure that I had some hotlink protection in place.

To accomplish this I've created a new directory under my site's default "images" directory and protected it from hotlinking with an Apache .htaccess file. For future reference here are the contents of the .htaccess file:

RewriteEngine On
RewriteCond %{HTTP_REFERER} !^http://(.+.)?example.com/ [NC]
RewriteCond %{HTTP_REFERER} !^$
RewriteRule .*.(jpe?g|gif|bmp|png)$ ../hotlink.gif [L]

The first line of the above code turns on the mod_rewrite engine in Apache. A requirement for the rewrite commands.

The second line matches any requests from the URL example.com [change this to suit your requirements]. The [NC] code means "No Case", meaning match the URL regardless of case.

The third line allows empty referrals.

Finally, the last line matches any files ending with the extension jpeg, jpg, gif, bmp, or png. This is then replaced by the hotlink.gif file [see below] residing in the above images directory.

An example no hotlinking image with message.

If you need to allow more domains to hotlink to your images you can simply duplicate line two. See the example below:

RewriteEngine On
RewriteCond %{HTTP_REFERER} !^http://(.+.)?example.com/ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.+.)?another-example.net/ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.+.)?one-more-example.org/ [NC]
RewriteCond %{HTTP_REFERER} !^$
RewriteRule .*.(jpe?g|gif|bmp|png)$ ../hotlink.gif [L]

Monday, October 29th, 2007

PHP 5 & Feed Updates

It's been a long time coming but my website [CrunchBang.org] is now finally running on PHP 5. My hosting provider performed the upgrade earlier this month and made the switch optional on a domain basis. Any domain on their servers can run either PHP version 4 [default] or upgrade to version 5 by adding a script handler in .htaccess:

Action php5-script /interpreters/php5-script
AddHandler php5-script .php

My development systems all run PHP 5 so the switch was a breeze. Hopefully from now on I'll be able to avoid stuff like this.

Also, I've been working on my Whird project over the weekend. I've now added feeds for individual tags and updated various features to improve usability. I've had to place some URL rewrites for the new feeds and I'm hoping that the various planets [Planet Ubuntu Users, Planet Ubuntu UK] don't get flooded — I apologise if they do :)


Friday, October 26th, 2007

Howto Set-up a Crontab File

Yesterday I mainly worked on some PHP backup scripts [not very exciting, but necessary.] The scripts are run at regular intervals and perform various data backups across numerous domains. To accomplish this I set-up some cron jobs that will automatically execute the scripts at set intervals.

This is not the first time that I've had to set-up cron jobs [I've got several that date back a few years.] I think that having the ability to set-up scheduled tasks is really quite important. Therefore I thought I'd blog about it for future reference.

What is cron?

Cron is a daemon/service that executes shell commands periodically on a given schedule. Cron is driven by a crontab, a configuration file that holds details of what commands are to be run along with a timetable of when to run them.

Creating a crontab file

You can create a crontab file by entering the following terminal command:

crontab -e

Entering the above command will open a terminal editor [Ubuntu uses Nano by default] with a new blank crontab file [or it will open an existing crontab if you already have one.] You can now enter the commands to be executed [see syntax below] before saving the file and exiting the editor. As long as your entries were entered correctly your commands should now be executed at the times/dates you specified. You can see a list of active crontab entries by entering the following terminal command:

crontab -l

Crontab syntax

A crontab file has six fields for specifying minute, hour, day of month, month, day of week and the command to be run at that interval. See below:

*     *     *     *     *  command to be executed
-     -     -     -     -
|     |     |     |     |
|     |     |     |     +----- day of week (0 - 6) (Sunday=0)
|     |     |     +------- month (1 - 12)
|     |     +--------- day of month (1 - 31)
|     +----------- hour (0 - 23)
+------------- min (0 - 59)

Crontab examples

Writing a crontab file can be a somewhat confusing for first time users [and the above table probably doesn't help much!] Therefore I've listed below some crontab examples:

* * * * * <command> #Runs every minute
30 * * * * <command> #Runs at 30 minutes past the hour
45 6 * * * <command> #Runs at 6:45 am every day
45 18 * * * <command> #Runs at 6:45 pm every day
00 1 * * 0 <command> #Runs at 1:00 am every Sunday
00 1 * * 7 <command> #Runs at 1:00 am every Sunday
00 1 * * Sun <command> #Runs at 1:00 am every Sunday
30 8 1 * * <command> #Runs at 8:30 am on the first day of every month
00 0-23/2 02 07 * <command> #Runs every other hour on the 2nd of July

As well as the above there are also special strings that can be used:

@reboot <command> #Runs at boot
@yearly <command> #Runs once a year [0 0 1 1 *]
@annually <command> #Runs once a year [0 0 1 1 *]
@monthly <command> #Runs once a month [0 0 1 * *]
@weekly <command> #Runs once a week [0 0 * * 0]
@daily <command> #Runs once a day [0 0 * * *]
@midnight <command> #Runs once a day [0 0 * * *]
@hourly <command> #Runs once an hour [0 * * * *]

Multiple commands

A double-ampersand "&&" can be used to run multiple commands consecutively. The following example would run command_01 and then command_02 once a day:

@daily <command_01> && <command_02>

Disabling email notifications

By default a cron job will send an email to the user account executing the cronjob. If this is not needed put the following command at the end of the cron job line:

>/dev/null 2>&1

Specifying a crontab file to use

As mentioned at the top of this post, you can create a new crontab file with the "crontab -e" command. However, you may already have a crontab file, if you do you can set it to be used with the following command:

crontab -u <username> <crontab file>

Therefore the following command…

crontab -u tux ~/crontab

…would set Tux's crontab file to that of the file named "crontab" residing in Tux's home directory.

Removing a crontab file

To remove your crontab file simply enter the following terminal command:

crontab -r

Further information

Refer to the man page for further information about crontab. Enter the terminal command:

man crontab

External links

Some external links for your browsing pleasure:

I think that pretty much covers the subject of cron jobs and crontab. Please feel free to comment if I've missed anything/made any boobs.


Thursday, October 18th, 2007

User Agent Sniffer

I've currently got several web projects at various stages of development. One thing that all of these projects have in common is that they all capture and manipulate user-agent stings.

What are user-agent strings?

User-agents strings are used by client applications such as web browsers, feed readers, bots and other software to identify themselves to the servers they are connecting to. The strings contain important information such as application type, version, language and operating system. A typical user-agent string might look like this:

Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.7 (like Gecko) (Kubuntu)

The above example is used to identify that the client is a Mozilla compatible Konqueror web browser running on Kubuntu Linux.

Collecting user-agent strings

To run tests on my projects I need some sample data to play around with [a list or database table of user-agent strings.] I figured that the best way to get this sample data would be to collect some user-agent strings from the wild. So, I wrote a quick PHP script to do just that.

I ran the script on this site [crunchbang.org] for ten days, starting on October 7th 2007. During that ten day period the script captured a total of 2272 unique user-agent strings. The captured list included both standard and non-standard strings.

A few facts about user-agent strings

After capturing the list I then edited the PHP script so that it would report a few facts. Here is a breakdown of what was returned:

1. At just 6 characters in length the shortest user-agent string captured was:

NG/2.0

2. The longest measured in at 205 characters, it was:

Mozilla/5.0 (compatible; MSIE 7.0; Windows; HTMLAB; .NET CLR 1.1.4322; 
MEGAUPLOAD 1.0; Seekmo; ZangoToolbar4.8.2; Alexa Toolbar; Hotbar 4.2.8.0) (compatible; 
Googlebot/2.1; +http://www.google.com/bot.html)

3. The average computed length of the user-agent strings was 91.2750880282 characters.

4. Most strings contained some non-alphanumeric characters, these were:

/ . ( ; - : ) + _ ! = , @ &  ' [ ] * ~ ? { }

5. The strangest user-agent string was:

Mmm.... Brains....

View the whole report

You can view the whole report here: http://crunchbang.org/misc/user-agent-report-2007-10-17.txt

Get the sample data

I thought it would be good to share the sample data. There's no private or confidential information in the data and I figure it may come in handy for other developers working on similar projects.

You can get the data as an ASCII file [one user-agent string per line] here: http://crunchbang.org/misc/sample-user-agents-ascii.txt

Or, as an SQL statement here: http://crunchbang.org/misc/sample-user-agents-mysql.txt

Get the PHP script

If you fancy having a go at collecting your own samples you can grab my PHP script here: http://crunchbang.org/misc/ua-sniffer.txt

The script requires the use of MySQL. Other than that it's a fairly straightforward affair. Just edit the four settings to define your database name, address, username and password.

I ran the script by calling it with a require_once statement. Note that the script also sets and reads a cookie so you'll need to call on it before outputting any data to the client.

require_once("ua-sniffer.php");

Once the script has collected some user-agent strings it is possible to query it and have it produce a basic report. You can do this by accessing the script through your browser like so:

http://www.example.com/ua-sniffer.php?report=true

Links to external references


Tuesday, October 2nd, 2007

301 Redirect with PHP

I've just had to permanently redirect an entire site. The site consisted of several hundred pages and on the face of it, it seemed like a daunting task. However two lines of PHP came to the rescue :-)

 Header( "HTTP/1.1 301 Moved Permanently" );
 Header( "Location: http://www.new-location.com" );

Luckily, each page on the site referred to a single configuration file and this made the process painless.

Tagged with: code, php, webdesign | Comments [0]


Sunday, September 30th, 2007

Silly Variable Names

They're not big and they're not clever. So how come they keep slipping into my code?

if(!empty($bum)){
    unload($bum);
}

Note to self: stop with the silly variable names already!

Tagged with: code, fun, programming | Comments [0]


Saturday, September 29th, 2007

robots.txt Adventure

If you're looking for information about robot.txt files you should read "robots.txt Adventure" at nextthing.org. The article is packed with original research and features some interesting facts and figures.

As for my own robots.txt, it's a pretty standard two line affair:

User-agent: *
Disallow:

Tagged with: code, webdesign | Comments [0]


Browse Posts by Tag

13th advocacy antispam artwork bash bbc bcs bittorrent bloggers blogs boobs bookmarklets cli code colour commands comments conduit crontab crunchbanglinux debian design development email fluxbuntu fonts fun gedit gimp gnome google gos hack hacks hosting images javascript language launchpad life lincslug linux lugradio madness memes misc monkeys motu mysql n95 networking nokia openbox openoffice opensuse packaging penguins php phpmyadmin podcast ppa progbox programming projects puppy python random rants realplayer revu scripts security shell software ssh terminal terminator themes tools twitter typography ubuntu ubuntucse unitedhosting video virtualisation webdesign whird wiki windows woot zombies