Site moved to Linode

Hello,

Three years since my last post. Much has happened. Kids are older, I’m wiser, I’m living at Fornebu outside Oslo. Call me to give you a full run-down.

This site has also moved to a UK Linode server since it’s fun to test out VPS services. Quite happy so far.

Your friend,

Willy

Simple but good encrypt user password script

In reference to the latest “Swedish password hacking scandal“:

MD5 hashed password are still widely used for storing passwords in  a database. Here’s Andrew Moore‘s contribution to help prevent this in the future, using Bcrypt. If you don’t have BCrypt installed, use phppass

<?php

class Bcrypt {
private $rounds;
public function __construct($rounds = 12) {
if(CRYPT_BLOWFISH != 1) {
throw new Exception(“bcrypt not supported in this installation. See http://php.net/crypt”);
}

$this->rounds = $rounds;
}

public function hash($input) {
$hash = crypt($input, $this->getSalt());

if(strlen($hash) > 13)
return $hash;

return false;
}

public function verify($input, $existingHash) {
$hash = crypt($input, $existingHash);

return $hash === $existingHash;
}

private function getSalt() {
$salt = sprintf(‘$2a$%02d$’, $this->rounds);

$bytes = $this->getRandomBytes(16);

$salt .= $this->encodeBytes($bytes);

return $salt;
}

private $randomState;
private function getRandomBytes($count) {
$bytes = ”;

if(function_exists(‘openssl_random_pseudo_bytes’) &&
(strtoupper(substr(PHP_OS, 0, 3)) !== ‘WIN’)) { // OpenSSL slow on Win
$bytes = openssl_random_pseudo_bytes($count);
}

if($bytes === ” && is_readable(‘/dev/urandom’) &&
($hRand = @fopen(‘/dev/urandom’, ‘rb’)) !== FALSE) {
$bytes = fread($hRand, $count);
fclose($hRand);
}

if(strlen($bytes) < $count) {
$bytes = ”;

if($this->randomState === null) {
$this->randomState = microtime();
if(function_exists(‘getmypid’)) {
$this->randomState .= getmypid();
}
}

for($i = 0; $i < $count; $i += 16) {
$this->randomState = md5(microtime() . $this->randomState);

if (PHP_VERSION >= ‘5’) {
$bytes .= md5($this->randomState, true);
} else {
$bytes .= pack(‘H*’, md5($this->randomState));
}
}

$bytes = substr($bytes, 0, $count);
}

return $bytes;
}

private function encodeBytes($input) {
// The following is code from the PHP Password Hashing Framework
$itoa64 = ‘./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789′;

$output = ”;
$i = 0;
do {
$c1 = ord($input[$i++]);
$output .= $itoa64[$c1 >> 2];
$c1 = ($c1 & 0x03) << 4;
if ($i >= 16) {
$output .= $itoa64[$c1];
break;
}

$c2 = ord($input[$i++]);
$c1 |= $c2 >> 4;
$output .= $itoa64[$c1];
$c1 = ($c2 & 0x0f) << 2;

$c2 = ord($input[$i++]);
$c1 |= $c2 >> 6;
$output .= $itoa64[$c1];
$output .= $itoa64[$c2 & 0x3f];
} while (1);

return $output;
}
}

$bcrypt = new Bcrypt(10);
$password = “agoodpassword”;echo $password;
$hash = $bcrypt->hash($password);echo ” = “.$hash.”<br>”;
$isGood = $bcrypt->verify(‘agoodpassword’, $hash);
if ($isGood) echo “OK<br/><br/>”;
else echo “NOT OK<br/><br/>”;

//Look, same password, different output! Mmmm, salt.

$bcrypt = new Bcrypt(10);
$password = “agoodpassword”;echo $password;
$hash = $bcrypt->hash($password);echo ” = “.$hash.”<br>”;
$isGood = $bcrypt->verify(‘agoodpassword’, $hash);
if ($isGood) echo “OK<br/><br/>”;
else echo “NOT OK<br/><br/>”;

?>

Quick and dirty url shortener

I neeeded a simple URL shortener for a framed image site (the framing wasn’t my idea). It had to work on non-php pages, so I came up with an iframe solution.

url/index.php (this file looks up the shortened URL and redirects)

<?php
$link = mysql_connect('localhost', 'user', 'password') or die('Could not connect: ' . mysql_error());
mysql_select_db('url') or die('Could not select database');
// Performing SQL query
$query = "SELECT * FROM links WHERE linkin = '".mysql_real_escape_string($_GET['u'])."'";
$result = mysql_query($query) or die('Query failed: ' . mysql_error());
$line = mysql_fetch_array($result, MYSQL_ASSOC);
header("Location: ".$line['linkout']." ");
?>
url/iframe.php (this file looks up or creates a short url, and gets the url to be processed from the url of the embedded iframe src. And then displays the link so the user can copy it.
<?php
//Check to only allow the URL shortener to work from certain domains
if (strstr($_SERVER["HTTP_REFERER"],"example.com"))
{
$link = mysql_connect('localhost', 'user', 'password') or die('Could not connect: ' . mysql_error());
mysql_select_db('url') or die('Could not select database');
// Performing SQL query
$query = "SELECT * FROM links WHERE linkout = '".mysql_real_escape_string($_GET['url'])."'";
$result = mysql_query($query) or die('Query failed: ' . mysql_error());
$num_rows = mysql_num_rows($result);
if ($num_rows==0) // if no match, create a new shortened url
{
$id=rand(10000,99999);
$shorturl=base_convert($id,20,36);
$query = "INSERT INTO links (linkout,linkin) VALUES ('".mysql_real_escape_string($_GET['url'])."','".$shorturl."')";
$result = mysql_query($query) or die('Query failed: ' . mysql_error());
echo 'Link to this page:<br><a href="http://example.com/url/?u='.$shorturl.'">http://img.example.com/url/?u='.$shorturl.'</a>';
}
else
{
$line = mysql_fetch_array($result, MYSQL_ASSOC);
echo 'Link to this page:<br><a href="http://example.com/url/?u='.$line['linkin'].'">http://img.example.com/url/?u='.$line['linkin'].'</a>';
}
} //End domain check
?>
</body>

contentpage.html (this is the page on which you want to display the shortened link, in my case a framed page)
The trick is getting the page url and passing it to the php iframe as a url parameter.  

<head>
<script type="text/javascript">

function sURL() {
	var href = escape(document.location.href);
	var site = "http://img.example.com/url/iframe.php?url="+href;
	document.getElementById('myIframe').src = site;
}
</script>
</head>
<body onLoad="sURL();">
<iframe id="myIframe" frameborder="0" name="myIframe" src="http://img.example.com/url/load.html" width="200" height="40" scrolling="no"></iframe>
</body>

url/load.html (this file is just a filler, displays a loader. Could also just be an empty file)
Get one at www.ajaxload.info

<html>
<body>
<img src="ajax-loader.gif">
</body>
</html>

If you have any questions, or if it doesn’t work as expected, just post a comment.

How to run php script every 15 minutes with launchd

On Mac OS X 10.6.6 I wanted a php script to be run every fifteen minutes past the hour , to check if something has been scheduled to run. I tried to use Lingon, but it couldn’t do exactly this. So I searched and found out I had to use an array.

The script below will use wget to run a php script at 00, 15, 30 and 45 minutes, every hour. Put it in /Library/LaunchAgents
and call it something like com.example.phpcheck.plist and restart the Mac.

<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd”>
<plist version=”1.0″>
<dict>
<key>Label</key>
<string>no.medieweb.autosend</string>
<key>ProgramArguments</key>
<array>
<string>/opt/local/bin/wget</string>
<string>-q</string>
<string>–delete-after</string>
<string>http://example.com/script.php</string>
</array>
<key>ServiceDescription</key>
<string>Check script every 15 minutes</string>
<key>StartCalendarInterval</key>
<array>
<dict>
<key>Minute</key>
<integer>0</integer>
</dict>
<dict>
<key>Minute</key>
<integer>15</integer>
</dict>
<dict>
<key>Minute</key>
<integer>30</integer>
</dict>
<dict>
<key>Minute</key>
<integer>45</integer>
</dict>

</array>
</dict>
</plist>

Garmin Forerunner 405cx and Mac are ok!

Garmin Forerunner 405xcAfter being inspired to start running after reading “Born to Run” by Christopher McDougall, I was very pleased to discover the many excellent technical devices you can use to track your run. I had only read about iPod and Nike+, but had to do a bit more research on the subject. A couple of coworkers already had exercise watches. One had a Polar watch, the other had the Forerunner 405. I had to test them both. I ended up getting the Garmin Forerunner 405CX. It has been reviewed extensively, but I wanted to write a bit about why I bought it.

  1. Mac compatible
  2. Very good web training journal
  3. No extra GPS unit

1. The Polar model I tested was PC only, and used a infrared/IRDA USB dongle to transfer the data. IrDA USB devices for Mac is very hard come by. So the only real option for a Mac user was to use a Boot Camp, or virtualization software. It also required PC software installed on a PC to view the exercise data. Since my research, polarpersonaltrainer.com was launched, and a few Polar models are now Mac compatible, so Polar’s heading in the right direction.But it was too little, too late.

2. I was first introduced to technical running, or whatever it’s called, with Runtracker for iPhone. Their web site is excellent and extremely user friendly. It also had a major facelift in the past week, and if they’d had a HR monitor device, I probably wouldn’t have bought the Forerunner. The exercise reports has a great GUI, and their service, support and transparency is probably the best of all.

Garmin’s web exercise journal is called connect.garmin.com, and also has a pretty and intuitive interface. Garmin offers software for Mac and PC if you really want it, but I don’t see any reason you’d want to. There might be features in the software that aren’t in the web application, but I don’t know what the could be. The activity report looks beautiful, and has tons of different features. If you click the green play arrow on the map, you get the entire run played out as a movie. You can also export the activity data to TCX, GPX, and KML (for Google Earth).

The Forerunner uses a system called ANT + to transfer the data from the device to the computer. You install the software and when the USB dongle is plugged in, it automatically detects when the paired device is nearby, determines if there are new workouts and uploads automatically to your web profile. You don’t have to click any buttons on the Forerunner. Very nice!

3. The Forerunner 405 has a built-in GPS in the watch, so you don’t need the extra device on your arm, like Polar does. This is a good thing. Just this weekend, I saw a guy running with it. He had the GPS device on his right arm, the watch on his arm, an iPod on the left arm and four water bottles on a waist belt. I think that’s just too much equipment to carry for a simple run.

On a final note, as I discovered yesterday, the Forerunner 405 has to be charged with a clip-charger and if you don’t use it for a week or two, the battery drains.Yeah yeah, I know it’s too long between runs, but that’s just how it goes sometimes, in a hectic family situation.

iStopMotion Applescript

I’ve bought iStopMotion Pro for HD time lapse recording to use with QuickCam Vision Pro for Mac. It works great, the camera is set to record in 720p and it’s really good in low-light conditions. iStopMotion makes it really easy to setup a time lapse recording. However, there’s one feature I miss and that is the possibility to have a schedule for starting and stopping the scripts. There’s no need to record anything after the workers have gone home for the day, and the output file becomes big enough as it is. So I’ve connected the MacBook to a mobile broadband modem that let’s me connect to the Mac with ScreenSharing and manually stop the recording. (The Mac is placed in a store and I can’t get to it outside regular opening hours.)

I asked the Boinx developer about the possibility of a schedule for time lapse and he replied that it’s possible to use AppleScript and iCal to stop and start the recording. So I brushed up on the ol’ AppleScript and created two very simple scripts.

One starts, the other one stops the time lapse recording. Create an iCal event for when you want it to start/stop, set “alarm” to “Run script” and select the script.

This saves me a lot of time since I no longer have to count on the broadband modem being connected and the setup can just run on its own.

iStopMotion-Apple Scripts

Edit: 30. april 2010:

Mac Mini Server with Promise SmartStor DS4600

Promise SmartStor DS4600 for Mac works great
Promise SmartStor DS4600 for Mac has good transfer speeds over RAID 5

I’ve just bought the Mac Mini Server with the Promise SmartStor DS4600 to use as the primary file server at Apeland Informasjon. The DS4600 is 4 disk DAS that connects with FW800 to the Mac Mini. It will be used on a gigabit network with 30 users.

I couldn’t find anyone who had tested this setup, so that’s what I’ll write a few lines about here. As for the Mac Mini Server, no other review is needed after Ars Technica has it covered just fine.

The DS4600 is setup as a RAID 5 volume right out of the box, with 2.7 TB available. All you have to do is connect it to the Mac Mini and it appears on the desktop, ready to rock. After you do some Server Admin magic, of course.

I’ve done some simple transfer speed tests over our Gigabit network, and the results are pretty good. Copying a a 5.51 Gb .mov file from my Mac Pro to the Mac Mini takes 2 mins 46 seconds and the transfer speeds is between 33,5 MB/s and 40 MB/s. (The speed is measured with iStat Menus on my Mac and MB is Megabytes per second. The Mac Mini and the Mac Pro is on the same Gb switch)

Copying the same .mov file back to my Mac Pro from the server takes 1 min 30 seconds and the transfer speed is between 58 MB/s and 65,4 MB/S and peaks at 70 MB/S. Not bad for a 15 000 NOK/$1800 setup. It’s wild that the tiny Mac Mini and the black SmartStor cube can pack so much punch. And the setup is oh-so-quiet. I like it.

If you have and specific questions or things you’d like me to check, just drop a note in the comments.

Microsoft Office 2008 SP2 12.2.0 update out

It fixes many things, like not displaying inserted images in labels when merging to new documents, which caused much gried and was highly time consuming. It also enables custom motion paths in Powerpoint and double-clicking anywhere in a slide will let you start typing. And the general application launch times are much improved.

BUT:

Office 2008 still handles networks saves the same though. I just posted this on the Office Mac SP2 blog post, it’s awaiting approval:

Thanks for many great fixes and features!

Especially the bug that made images disappear when merging labels in Word. Saves me so much time! Question: Office 2008 still seems to handle saves to network volumes the same way, using the .TemporaryItems/folders.501/TemporaryItems hidden volume way, 501 being the user id of the client-Mac.

Pretty much all other Mac applications seems to handle this a more logical way, like just having a lock file in the same directory as the document. This issue has been around at least since Office 2004. There’s no plans for changing this? It causes much headache in businesses where many users share one drive using AppleShare.

If I could get a response from someone who can tell me why this is, I’d be very happy.

Thanks, Willy T. Koch Norway

Maybe not the right place to post something like that, it might not be approved, but I had to ask them. This issue has been driving me crazy for years. I just really want to know why they can’t change this. Adobe InDesign puts a ~file in the same folder as the .indd file. Plain and simple. Why do Microsoft need to bring in the user id of the Mac user? In most cases this number is 501 since that’s the first user created on the Mac.

Every time an update is released for Office 2008, I prey that something has been done with this issue. And now with SP2 out and no fix, it will probably be a long way comin’.

New website at 0101.no

Why hello there. Just installed WordPress to see what it’s life. So far, I really like it! I have another site at asdf.no but wanted to use a real blogging tool with all kinds of fun plugins.

Lately I’ve been inspired to be more productive and create original content on the Internet. That’s my goal. To publish something here that can’t be found elsewhere. I’ve been thinking about this for a while, but it was Andy Baio’s post that gave me the extra kick in the arse. His idea of posting something original every day is a really great idea. I’m not going to post something new every day, being the father of 1-year old twins and working full time at Apeland Informasjon prevents that. But when I do post something here, I’ll try really hard to make it original to the Internet. What I post will be not be found elsewhere, and I’ll try to keep it worth reading. High expectations are good!

So, come back later for new stuff!

Once in a while, I post stuff.