LimerickDB
There once was a buggy AI
Who decided her subject should die.
When the plot was uncovered,
The subjected discovered
That sadly the cake was a lie.
There once was a buggy AI
Who decided her subject should die.
When the plot was uncovered,
The subjected discovered
That sadly the cake was a lie.
PHPT is the kind framework that encourages testing simply by making everything so easy. All that’s needed is a file with your PHP code and expected output. It wont replace SimpleTest or PhpUnit for anything complicated (say, like PHP itself…) but it seems to be just what I’m after.
There’s little documentation about (PHP QA website was the best resource I found), but thanks to its simplicity all you need to get started is an example or two.
Sample phpt file
--TEST--
AusPostCheck class
--FILE--
<?php
require_once("../../../test/newGuiTest/bootstrap.php");
require_once("../check_contact_details.php");
var_dump(AusPostCheck::SuburbStatePostcodeMatch('Windsor', 'VIC', '3181'));
var_dump(AusPostCheck::SuburbStatePostcodeMatch('Windsor', 'VIC', '3182'));
var_dump(AusPostCheck::SuburbStatePostcodeMatch('Windsor', 'NSW', '3181'));
var_dump(AusPostCheck::SuburbStatePostcodeMatch('Prahran', 'VIC', '3181'));
var_dump(AusPostCheck::SuburbStatePostcodeMatch('Foobar', 'VIC', '3181'));
?>
--EXPECT--
string(5) "MATCH"
string(8) "NO_MATCH"
string(8) "NO_MATCH"
string(5) "MATCH"
string(9) "NO_SUBURB"
Sample output
margaret ~/tests $ phpt
PHPT Test Runner v0.1.1alpha
.
Test Cases Run: 1, Passes: 1, Failures: 0, Skipped: 0
Think I’m getting the hang of this Kara thing. Damage stats for Prince:
| Character | Damage | DPS | Comment |
|---|---|---|---|
| Ardren | 271565 (23.8%) | 863.2 | Fire Mage (Me!) |
| Sormoran | 189466 (16.6%) | 577.4 | Shadow Priest |
| Quickcrit | 180886 (15.8%) | 541.5 | Hunter |
| Umparevoker | 174769 (15.3%) | 533.9 | Combat Rogue |
| Llonjudd | 160488 (14.1%) | 549.7 | Warlock |
| Taeghas | 87207 (7.6%) | 255.4 | Prot Warrior (Main Tank) |
| Noobjuicer | 73363 (6.4%) | 248.6 | Prot Warrior |
This sounds like a fun project: Extract all the data out of recount (WoW addon) and present it as a webpage.
Updated with next weeks damage. Looks much better
| Character | Damage | DPS | Comment |
|---|---|---|---|
| Ardren | 270364 (23.7%) | 1017.6 | Fire Mage (Me!) |
| Llonjudd | 189502 (16.6%) | 739.1 | Warlock |
| Mastagrinda | 179299 (15.7%) | 641.6 | Hunter (Pet not merged) |
| Umparevoker | 169872 (14.9%) | 627.3 | Combat Rogue |
| Sormoran | 164751 (14.5%) | 632.7 | Shadow Priest |
| Taeghas | 72767 (6.4%) | 259.9 | Prot Warrior (Main Tank) |
| Noobjuicer | 67968 (6.0%) | 279.5 | Prot Warrior |
| Rex | 22738 (2.0%) | 92.4 | Mastagrinda’s Pet |
$row = $table->tr();
if(!($amIAltOrNot = !$amIAltOrNot))
{
$row->class = "alt";
}
// Edit: Much better now
$row = $table->tr();
$row->class = ($amIAltOrNot = !$amIAltOrNot) ? "" : "alt";
This website is now hosted on Slicehost (along with section99.net). It’s a little early to know how it will turn out, but so far I’m loving having not only a shell, but root access.
Signing up was completely painless and the the VPS was provisioned within minutes with several different operating system options (though I’m aware that this can sometimes take weeks depending on current capacity). While I run the bleeding edge version of Ubuntu at work, I opted for the slightly safer option, Ubuntu 6.06 LTS.
Setting up Lighty / PHP and Mysql took mere minutes thanks to apt-get and Debian’s sane default configuration. WordPress took a tiny bit of fiddling in Mysql so I could test it on another domain name, but aside from that, everything has been very painless.
I’m hoping that this gives me the chance to play with some webpy and even (maybe) some rails applications.
The only problem I’ve had (except for screwing up the DNS) is editing my crontab when loged in as a normal user. I’m unable to edit it due to a weird permission error. While it’s not a huge problem (root can edit anybodies crontab easily) but it’s odd that the only real information I can find is related to an old Debian bug.
Code
<?php
/*
PHP implementation of a common programming problem:
Reversing a singly linked list
*/
error_reporting(E_ALL | E_STRICT);
// This is our basic node
class WordNode
{
public $word;
public $nextNode;
public function __construct($word = null)
{
$this->word = $word;
}
// Print all content of this node, and linked nodes
public function __toString($separator = '')
{
$buffer = '';
$current = $this;
do
{
// Append the separator as long as there is a next node
$buffer .= $current->word . (($current->nextNode !== null) ? $separator : '');
}
while(($current = $current->nextNode) !== null);
return $buffer;
}
}
// Takes an array and turns it into a linked list
// (Remember this is purely an academic exercise :-)
function buildWordNodeList($sourceArray)
{
// First step create the linked list
$firstNode = new WordNode($sourceArray[0]);
$lastNode = $firstNode;
foreach(array_slice($sourceArray, 1) as $word)
{
$thisNode = new WordNode($word);
$lastNode->nextNode = $thisNode;
$lastNode = $thisNode;
}
return $firstNode;
}
// Inplace reverse
function reverseWordNodeListInplace(WordNode &$head)
{
// Init the loop by separating the top node, and
// keeping track of what is left ($tail)
$tail = $head->nextNode;
// This is set to null as it will end up being the
// last node and shouldn't point anywhere
$head->nextNode = null;
while($tail !== null)
{
// Take the next node, and seperate it, and again
// keep track of what's left
$next = $tail;
$tail = $next->nextNode;
// Now make this node the parent of the previous top node
$next->nextNode = $head;
// This node is now at the top
$head = $next;
}
}
$list = buildWordNodeList(array("a","b","c","d","e","f","g","h", "i", "j", "k"));
echo $list . "\n";
reverseWordNodeListInplace($list);
echo $list . "\n";
reverseWordNodeListInplace($list);
echo $list . "\n";
echo $list->__toString(" ") . "\n";
?>
Output
abcdefghijk
kjihgfedcba
abcdefghijk
a b c d e f g h i j k
I’m not allowed to complain about raiding any more.
Went to Zul’Aman a couple of weeks back, after a few tries took down the first boss, and then a couple of tries on the second boss, but things didn’t go so well (I kinda wiped the raid). Also did a Kara run with 7 guildies to one shot everything up to Curator (and then called it without attempting). Was pretty happy then about the guilds progress, alot of it is thanks to a > Kara geared tank who been organizing the guild raids.
This week after a fairly epic Kara run (just over six hours):
Just a little bit of an improvement over last time :-)
Can’t have a post about PHP at the top of the page for more that an couple of days. So on with the WoW gloating and moaning.
Stats are looking pretty good. Hit is suffering a little though (says someone who can count his Kara raids on one hand :-(
Overall, very happy with my mage… Just running out of things to aim for, there is one more item I want for badges, but I’m only 5 / 60 so far. I would really like to run Kara on a regular basis with a group of dedicated people, I don’t think it’s possible with this guild, and who on earth wants a Mage for Kara :-(
<?php
/*
Some hacked up code for Very Simple (Pretend) SQL Paramaters
-- For when you don't have PDO, or just can't be bothered
Examples:
>>> SQL("SELECT * FROM users WHERE id=? AND name LIKE ?", 123, '"123\"');
SELECT * FROM users WHERE id=123 AND name LIKE "\"123\\\""
>>> SQL("INSERT INTO user (nameFirst, nameLast) VALUES (?, ?)", "Fred", "Nurk");
INSERT INTO user (nameFirst, nameLast) VALUES ("Fred", "Nurk")
*/
function SQL($sql)
{
$params = func_get_args();
$params = array_map('mysql_real_escape_string', $params);
$sql = explode('?', $sql);
if(count($params) != (count($sql)-1))
{
throw new Exception(sprintf("Incorrect number of paramaters. Expected %d got %d", count($sql)-1, count($params)));
}
$newSql = '';
for($i = 0; $i < count($params); $i++)
{
$newSql .= $sql[$i] . (is_numeric($params[$i]) ? $params[$i] : '"' . $params[$i] . '"');
}
return $newSql . $sql[$i];
}
?>
Update: This is not only the wrong way to escaping, but introduces more bugs. Don’t ever use.
PHP version of the Python script located at http://decenturl.com/tools#api.
Update: Thanks to a quick update by Ben, DecentURL now returns valid JSON, so the quote workaround is no longer needed.
<?php
/*
PHP interface for the DecentUrl service
by Matthew D (project-2501.net)
Based on the Python script by Ben Hoyt
See http://decenturl.com/tools#api
Example:
<?php
require_once("decenturl_interface.php");
// returns: "youtube/medieval-helpdesk-with-english"
DecentUrl::Get('http://youtube.com/watch?v=pQHX-SjgQvQ');
// returns: "http://youtube.com/watch?v=pQHX-SjgQvQ"
DecentUrl::Resolve('youtube/medieval-helpdesk-with-english');
// returns: array("DecentURL - Making ugly URLs decent", "making-ugly-urls-decent")
DecentUrl::Title('http://decenturl.com/');
// returns: "brush.co.nz"
DecentUrl::Domain('http://brush.co.nz');
// throws a DecentUrlException("resolve request failed: notfound")
DecentUrl::Resolve('baddy');
?>
*/
class DecentUrlException extends Exception {}
class DecentUrl
{
const BASE_URL = 'http://decenturl.com/api-';
// Create or get decent URL from given ugly one and return it
public static function Get($url, $title="")
{
$response = self::Request("get", array("u" => $url, "t" => $title), 2);
return $response[0];
}
// Resolve decent URL and return ugly original
public static function Resolve($decentUrl)
{
$response = self::Request("resolve", array("d" => $decentUrl), 2);
return $response[0];
}
// Return tuple of full <title> and decent title for given URL
public static function Title($url, $maxLength = 1000)
{
return self::Request("title", array("u" => $url, "l" => $maxLength), 2);
}
// Return URL's base domain
public static function Domain($url, $maxLength = 1000)
{
$response = self::Request("domain", array("u" => $url, "l" => $maxLength), 1);
return $response[0];
}
// Call generic DecentUul API function, throw DecentUrlException if not ok
private static function Request($type, $parameters, $expectedResponseSize = false)
{
// Take a key value pair, and join them together, making sure to
// urlencode the value
foreach($parameters as $key => $value)
{
$parameters[$key] = sprintf("%s=%s", $key, urlencode($value));
}
$queryString = implode("&", array_values($parameters));
$url = sprintf("%s%s?%s", self::BASE_URL, $type, $queryString);
$contents = file_get_contents($url);
$response = json_decode($contents);
if($response == null)
{
throw new DecentUrlException("Response was not valid JSON");
}
if($response[0] != "ok")
{
throw new DecentUrlException("{$type} request failed: {$response[0]}");
}
// Remove the first element (which we proved was 'ok' above)
$trimedResponse = array_slice($response, 1);
// If requested, we check to see that the response is the correct
// size.
if(($expectedResponseSize !== false) && (count($trimedResponse) != $expectedResponseSize))
{
throw new DecentUrlException("{$type} request failed: expected {$expectedResponseSize} fields, got " . count($trimedResponse));
}
return $trimedResponse;
}
}
?>