i hate working with dates

This little snippet gets all the days in a month, and groups them by week.

<?php

    error_reporting(E_ALL);

    // Return an array of all the days in a month grouped by week number
    // (Sunday is considered to be the first day of the week)
    function weeksInMonth($month, $year)
    {
        $firstDay    = mktime(0, 0, 0, $month, 1, $year);
        $daysInMonth = date('t', $firstDay);
       
        $week        = 1;
        $breakdown   = array();
       
        for($i = 1; $i <= $daysInMonth; $i++)
        {
            $date = mktime(0, 0, 0, $month, $i, $year);
            $day  = date('l', $date);
           
            // Sunday triggers the start of a new week, except if it's
            // also the first day of the month.
            if(($day == 'Sunday') && ($i != 1))
            {
                $week++;
            }
           
            $breakdown[$week][] = $date;
        }
       
        return $breakdown;
    }
   
   
    $results = monthToWeek(6, 2008);
   
    printf("There are %d weeks in June 2008\n\n", count($results));
   
    foreach($results as $weekNumber => $days)
    {
        printf("Week %d\n", $weekNumber);
       
        foreach($days as $day)
        {
            printf("%10s  %s\n", date("l", $day), date("Y-m-d", $day));
        }
       
        printf("\n");
    }

/*
There are 5 weeks in June 2008

Week 1
    Sunday  2008-06-01
    Monday  2008-06-02
   Tuesday  2008-06-03
 Wednesday  2008-06-04
  Thursday  2008-06-05
    Friday  2008-06-06
  Saturday  2008-06-07

Week 2
    Sunday  2008-06-08
    Monday  2008-06-09
   Tuesday  2008-06-10
 Wednesday  2008-06-11
  Thursday  2008-06-12
    Friday  2008-06-13
  Saturday  2008-06-14

Week 3
    Sunday  2008-06-15
    Monday  2008-06-16
   Tuesday  2008-06-17
 Wednesday  2008-06-18
  Thursday  2008-06-19
    Friday  2008-06-20
  Saturday  2008-06-21

Week 4
    Sunday  2008-06-22
    Monday  2008-06-23
   Tuesday  2008-06-24
 Wednesday  2008-06-25
  Thursday  2008-06-26
    Friday  2008-06-27
  Saturday  2008-06-28

Week 5
    Sunday  2008-06-29
    Monday  2008-06-30
*/

?>

Posted by Matthew on August 21st, 2008

Filed under php, programming | No Comments »

K100D Gallery Added

Just added a couple of quick photos to the k100d gallery. Really wish I could have speant longer watching the surfers near The Spit

Camera is Pentax K100D 6MP with a Sigma 70-300 / Sigma 28-70 F2.8

Thumbnail for: 20080713 Springbrook.jpeg
20080713 Springbrook.jpeg

(924 x 624)
137 kB
Thumbnail for: 20080722 Birra Burra.jpeg
20080722 Birra Burra.jpeg

(578 x 924)
148 kB
Thumbnail for: 20080726 The Spit 1.jpeg
20080726 The Spit 1.jpeg

(924 x 579)
127 kB
Thumbnail for: 20080726 The Spit 2.jpeg
20080726 The Spit 2.jpeg

(924 x 624)
178 kB
Thumbnail for: 20080726 The Spit 3.jpeg
20080726 The Spit 3.jpeg

(924 x 424)
113 kB
Thumbnail for: 20080726 The Spit 4.jpeg
20080726 The Spit 4.jpeg

(924 x 533)
125 kB
Thumbnail for: 20080726 The Spit 5.jpeg
20080726 The Spit 5.jpeg

(924 x 555)
140 kB

Posted by Matthew on August 10th, 2008

Filed under random | No Comments »

auth.log noise

Below are the top 50 login names when trying to gain access to this web server over the last 4 weeks

Name Attempts
root 3273
admin 119
test 110
mysql 44
guest 41
user 37
oracle 37
temp 25
sales 24
info 21
webmaster 21
postgres 21
dan 18
robert 18
student 17
ftpuser 17
ftp 17
richard 16
apache 16
web 15
adm 15
webadmin 15
john 15
paul 15
office 15
tony 14
james 14
postfix 13
michael 13
alex 13
david 13
amanda 13
adam 12
mike 12
staff 12
steven 12
recruit 12
jeff 12
pgsql 12
library 12
username 12
frank 12
susan 11
cyrus 11
dave 11
gast 10
postmaster 10
nagios 10
martin 10
admins 10

Note: No external connections are allowed to log in as root (of course)
Note2: After 5 failed login attempt, the IP address is temporary banned (fail2ban)

Posted by Matthew on July 7th, 2008

Filed under Uncategorized | 1 Comment »

import life

A console based implementation of Conway’s Game of Life in Python.
As fascinating as it is useless.

#!/usr/bin/python

import sys
import random
import time
import os
import copy

WIDTH = 32
HEIGHT = 16

class Grid:
    def __init__(self, width, height):
        self.width  = width
        self.height = height
        self.create_blank_grid()

    def create_blank_grid(self):
        self.grid = []

        for x in range(0, self.width):
            self.grid.append([0 for y in range(0, self.height)])

    def seed(self, chance = 0.4):
        for x in range(0, self.width):
            for y in range(0, self.height):
                if random.random() < chance:
                    self.grid[x][y] = 1
                else:
                    self.grid[x][y] = 0

    def add_glider(self):
        self.grid[1][0] = 1
        self.grid[2][1] = 1
        self.grid[0][2] = 1
        self.grid[1][2] = 1
        self.grid[2][2] = 1
   
   
    def __str__(self):
        buffer = ''

        for y in range(0, self.height):
            for x in range(0, self.width):
                str = ' '
                if self.grid[x][y] == 1:
                    str = '#'
                   
                buffer += str
            buffer += '\n';
        buffer += '\n';

        return buffer

    def get_number_neighbours(self, x, y):

        def get_value(i,j):
            try:
                return self.grid[i][j]
            except:
                return 0

        number_neighbours = get_value(x-1, y-1) + get_value(x, y-1)   + get_value(x+1, y-1) +  \
                            get_value(x-1, y)   +                       get_value(x+1, y)   +  \
                            get_value(x-1, y+1) + get_value(x, y+1)   + get_value(x+1, y+1)

        return number_neighbours


    def tick(self):
        new_grid = copy.deepcopy(self.grid)

        for x in range(0, self.width):
            for y in range(0, self.height):

                number_neighbours = self.get_number_neighbours(x,y)

                if self.grid[x][y] == 1:
                    if number_neighbours < 2:
                        new_grid[x][y] = 0
                    elif number_neighbours > 3:
                        new_grid[x][y] = 0
                else:
                    if number_neighbours == 3:
                        new_grid[x][y] = 1

        self.grid = new_grid

if __name__ == "__main__":
    grid = Grid(WIDTH, HEIGHT)
    # chance for a cell to be 'alive'
    grid.seed(0.2)
    # grid.add_glider()

    # 100 generations
    for x in range(0, 100):
        os.system('clear')
        print grid
        grid.tick()
        time.sleep(1)

Posted by Matthew on June 20th, 2008

Filed under Uncategorized | No Comments »

Pretending PHP doesn’t suck

<?php

// Perhaps the simplest practical use of a fold?
//
// (While this is fairly consise (even in PHP) it calculates the length of a
// string 2n-2 times [which is n-2 times more than needed])
function getLongestWord($words)
{
  $fun = create_function('$a,$b', 'return (strlen($a) > strlen($b)) ? $a : $b;');

  return array_reduce($words, $fun);
}

// This looks a little better, but it loses a lot of the simplicity of the above
function getLongestWord_2($words)
{ 
  $map  = create_function('$a', 'return array($a, strlen($a));');
  $fold = create_function('$a,$b', 'return ($a[1] > $b[1]) ? $a : $b;');

  $word = array_reduce(array_map($map, $words), $fold);

  return $word[0];
}

$words = array('a', 'bb', 'ccc', 'dd', 'eeee', 'fff', 'gg');

var_dump(getLongestWord($words));
// string(4) "eeee"

var_dump(getLongestWord_2($words));
// string(4) "eeee"

?>

Is there an even simpler way to find the longest string in an array?

Posted by Matthew on June 19th, 2008

Filed under Uncategorized | No Comments »

Extracing links from HTML using PHP

Many months ago there was a PHP competition to make the smallest script to extract all the links from a document. I’ve lost a link to the actual site, but the rules and conditions were set up expecting everyone to solve the problem with regular expressions. In my opinion relying on regular expressions to parse HTML would be a terrible idea (and may actually be impossible to do with a normal engine), so I tried a slightly different approach:

Program listing. 162 Bytes.

<?php foreach(@DOMDocument::loadHTMLFile($argv[1])->getElementsByTagName('a') as $t)@$u[$t->getAttribute('href')]=0;foreach($u as $k=>$v)echo $k!=''?"$k\n":'';?>

Expanded program listing with comments

<?php

    // Using PHP DOMDocument class, we load in a HTML file from the
    // command line and extract all the 'a' tags.  The '@' is used to
    // suppress any parse errors
    foreach(@DOMDocument::loadHTMLFile($argv[1])->getElementsByTagName('a') as $t)
    {
        // We get the value of the href attribute and store is as a
        // key in $u.  This is so each URL only appears once without
        // having to call array_unique().  '@' is used to suppress the
        // error when we add the first element to a non-existent array
        // $u (which PHP then kindly creates for us)
        @$u[$t->getAttribute('href')]=0;
    }
   
    // Finally we iterate over the array of URLS ($u) and if the key
    // (which is the actual URL) is empty don't do anything, else print
    // the url followed by a new line.
    foreach($u as $k=>$v)
    {
        echo $k != '' ? "$k\n" : '';
    }

?>

Posted by Matthew on May 1st, 2008

Filed under php, programming | No Comments »

Simple type checking in PHP

<?php

    error_reporting(E_ALL | E_STRICT);

/*

Manual optional type checking for PHP functions
   
Basic example:
   
    function log_error($line_number, $filename, $desc)
    {
        CheckFunctionArgs('integer', 'string', 'string');
        [snip]
    }
   
Object example:
   
    class LogObject {}
    function register_object($obj)
    {
        //  Check for an object
        CheckFunctionArgs('object');   

        //  When an object is passed, you can optionally check for the class name
        CheckFunctionArgs('LogObject');

        [snip]
    }

Wildcard example:

    function log_anything($line, $thing)
    {
        //  '*' really means anything, included true/false/null or an empty string
        //  however it doesn't mean the argument in optional
        CheckFunctionArgs('integer', '*');
    }

Notes:

    Throws an exception on error
    No support for functions that take a variable number of arguments
    Must define the types of all arguments
    The type '*' acts as a wild card, matching anything (including null)
    Works with public and private methods in classes
   
*/


    function CheckFunctionArgs()
    {
        $types = func_get_args();
        $stack = debug_backtrace();

        //  Make sure there is some stack information
        //  Stack[1] contains the details about the function that called this function
        if(!isset($stack[1]))
        {
            throw new Exception("No function stack present.  Make sure CheckFunctionArgs() isn't called from the global scope");
        }

        //  The arguments that were passed to the function we are checking
        $arguments = $stack[1]['args'];


        //  Get the name of the class/function/file
        $functionClass = (isset($stack[1]['class'])) ? $stack[1]['class'] . "::" : '';
        $functionFile  = (isset($stack[1]['file'])) ? basename($stack[1]['file']) . ':' . $stack[1]['line'] : '[No file information]';
        $functionName  = "{$functionClass}{$stack[1]['function']}()";
       
       
        //  Basic check, make sure the correct numbers of arguments were passed
        if(count($arguments) != count($types))
        {
            $passed = count($arguments);
            $expected = count($types);

            throw new Exception("Incorrect number of argumemts passed to {$functionName} in {$functionFile}.  Expected {$expected} got {$passed}");
        }


        //  Now try and check each argument
        for($i = 0; $i < count($arguments); $i++)
        {
            //  Allow a check to be skiped, if the type equals '*'
            if($types[$i] == '*')
            {
                continue;
            }

            $argumentType = gettype($arguments[$i]);
           
            //  Check basic types like integer/object ect
            if($argumentType == $types[$i])
            {
                continue;
            }

            //  Check to see if the type matches the classname of an object
            if(($argumentType == 'object') && (get_class($arguments[$i]) == $types[$i]))
            {
                continue;
            }

            throw new Exception("Incorrect argument passed to {$functionName} in {$functionFile}.  Argument {$i} was type {$argumentType} expected {$types[$i]}");
        }


        return true;
    }

    //  Some really basic tests

    function assertException($fun, $args)
    {
        try
        {
            call_user_func_array($fun, $args);
            throw new Exception(sprintf("Error: No exception thrown in function %s\n", $fun));
        }
        catch(Exception $e)
        {
        }
    }

    function assertNoException($fun, $args)
    {
        try
        {
            call_user_func_array($fun, $args);
        }
        catch(Exception $e)
        {
            throw new Exception(sprintf("Error: Exception thrown in function %s\n", $fun));
        }
    }


    function test_string($a)
    {
        CheckFunctionArgs('string');
    }

    assertNoException('test_string', array('abc'));
    assertNoException('test_string', array(''));
    assertNoException('test_string', array('123'));

    @assertException('test_string', array());
    assertException('test_string', array(123));
    assertException('test_string', array(null));


    function test_integer($a)
    {
        CheckFunctionArgs('integer');
    }

    assertNoException('test_integer', array(0));
    assertNoException('test_integer', array(123));

    @assertException('test_integer', array());
    assertException('test_integer', array(null));
    assertException('test_integer', array(''));
    assertException('test_integer', array('a'));
    assertException('test_integer', array(1.0));
    assertException('test_integer', array(1.2));


    function test_wildcard($a)
    {
        CheckFunctionArgs('*');
    }

    assertNoException('test_wildcard', array('a'));
    assertNoException('test_wildcard', array(1233));
    assertNoException('test_wildcard', array(null));
    @assertException('test_wildcard', array());


    class Foobar {}
    $foobar = new Foobar();
    function test_classname($a)
    {
        CheckFunctionArgs('Foobar');
        CheckFunctionArgs('object');
    }

    assertNoException('test_classname', array($foobar));
    assertException('test_classname', array('Foobar'));

?>

Posted by Matthew on April 15th, 2008

Filed under php, programming | 2 Comments »

sizeof(int) = 68

Pankaj Kumar has a slightly disturbing look at memory usage in PHP.

Each element requires a value structure (zval) which takes 16 bytes.
Also requires a hash bucket - which takes 36 bytes. That gives 52 bytes
per value. Memory allocation headers take another 8 bytes*2 - which
gives 68 bytes. Pretty close to what you have.

Posted by Matthew on April 2nd, 2008

Filed under php, programming | No Comments »

fun with anagrams

<?php

define('WORD_LIST_FILENAME', '/usr/share/dict/words');


class AnagramLookup
{
    private $lookup;

    //  Loads a file with one word per line
    private function load_word_list($filename)
    {
        $lines = file($filename);                     // One word per line
        $lines = array_map('trim', $lines);           // Strip any excess whitespace
        $lines = array_filter($lines, 'ctype_alpha'); // Words been to match [a-zA-Z]
        $lines = array_map('strtolower', $lines);     // Set all the words to lowercase
        $lines = array_unique($lines);                // Remove any duplicate words
        $lines = array_diff($lines, array(''));       // Remove any empty lines

        return $lines;
    }

    //  Sort the individual letters in a string
    //  i.e.   tale  =>  aelt
    private function sort_letters($word)
    {
        $letters = str_split($word);
   
        sort($letters);
   
        $sorted_word = implode('', $letters);
   
        return $sorted_word;
    }

    //  Generate our lookup table.  This takes ~1.5second for 70,000 words
    //  $lookup ends up looking like:
    //
    //  $lookup[4] = array
    //  (
    //    'aelt' => array('late', 'tale', 'leta', 'teal'),
    //    'belu' => array('blue', 'lube'),
    //    [etc...]
    //  )
    //  $lookup[5] = array
    //  (
    //    'allms' => array('small', 'malls'),
    //    [etc...]
    //  )
    //
    //  4 and 5 are the word lengths, while 'aelt', 'belu' and 'allms'  contains
    //  an array of all the words that can be spelt using these letters
    public function __construct($filename)
    {
        $word_list = $this->load_word_list($filename);

        $lookup = array();

        foreach($word_list as $word)
        {
            $length = strlen($word);

            if(!isset($lookup[$length]))
            {
                $lookup[$length] = array();
            }

            $sorted_word = $this->sort_letters($word);

            if(!isset($lookup[$length][$sorted_word]))
            {
                $lookup[$length][$sorted_word] = array();
            }

            $lookup[$length][$sorted_word][] = $word;
        }

        $this->lookup = $lookup;
    }

    //  Return all the anagrams of the passed word
    public function lookup_word($word)
    {
        $word_length = strlen($word);
        $sorted_word = $this->sort_letters($word);

        if(isset($this->lookup[$word_length][$sorted_word]))
        {
            return $this->lookup[$word_length][$sorted_word];
        }

        return array();
    }

    //  Return an array of all the sets of anagrams with a specific length
    //
    //  Example result for a word length of 14:
    //
    //  array
    //  (
    //    [0] => array('certifications','rectifications'),
    //    [1] => array('impressiveness','permissiveness'),
    //    [2] => array('tablespoonfuls','tablespoonsful'),
    //  )
    public function all_of_length($word_length)
    {
        if(!isset($this->lookup[$word_length]))
        {
            return array();
        }

        $results = array();

        foreach($this->lookup[$word_length] as $words)
        {
            if(count($words) > 1)
            {
                $results[] = $words;
            }
        }

        return $results;
    }
}


$anagram = new AnagramLookup(WORD_LIST_FILENAME);

printf("Anagrams of 'blue': %s\n", implode(', ', $anagram->lookup_word('blue')));
printf("Anagrams of 'late': %s\n", implode(', ', $anagram->lookup_word('late')));
printf("Anagrams of 'slow': %s\n", implode(', ', $anagram->lookup_word('slow')));
printf("Anagrams of 'seven':  %s\n", implode(', ', $anagram->lookup_word('seven')));
printf("Anagrams of 'anagram': %s\n", implode(', ', $anagram->lookup_word('anagram')));

printf("All anagrams of word length 14\n");

foreach($anagram->all_of_length(7) as $words)
{
    printf(" * %s\n", implode(', ', $words));
}


?>

Posted by Matthew on March 28th, 2008

Filed under php, programming | 1 Comment »

Javascript…

Javascript is both infuriating and awesome at the same time. I don’t think I’ve ever speant so much time tracking down annoying bugs (even compared to PHP), yet at the same time it makes functions like the one below very simple to write.

For reference, the below code returns a `getter` method that we use to instantiate objects via a cache system.

var buildSimpleObjectGetter = function(cacheRef, objectRef)
{
   var f = "buildSimpleObjectGetter()";
   UTILS.checkArgs(f, arguments, [ObjectCache, Function]);
   
   return function(idRecord, idArg)
   {
      return cacheRef.get('' + idArg, function()
      {
         return new objectRef(idRecord, idArg);
      });
   }
}

Update 20080327:

On the topic of stupid Javascript bugs, who thought auto terminating lines was a good default!

function getWords()
{
    return
    [
        'Hello',
        'World!'
    ];
}

console.info(getWords());

// Ouput
// >>> undefined

Posted by Matthew on March 23rd, 2008

Filed under javascript | No Comments »