After being more than frustrated with my Internet Service Provider I decided to start monitoring their service for them, and I figured that if I monitored one, I might as well as monitor all of the local ISP’s in the area. This is the result: Connectivity Monitor.

The following code is used to record the data. Because the script records more than average latency, I’ll leave the graph creation to you. This script is ment to be run from the command line (and NOT called by a web server, remember screen is your friend!) I make no claims as to whether this is the most efficient code but it works great for my purposes!

// RRD Filename
$file = './ISP-Connectivity.rrd';

// Image Destination
$imgdest = './images';

// Hosts to monitor (Use your ISP'a Gateway) (Add more as needed)
$target[] = array('127.0.0.1', 'Localhost');

function termination() {
}

function error_out($msg = null, $clean = true) {
	if ( $clean == true ) {
		if ( !is_null($msg) ) {
			echo 'ERROR: ' .$msg . "\n";
		}
		exit;
	} else {
		if ( !is_null($msg) ) {
			echo 'ERROR: ' .$msg . "\n";
		}
		exit(1);
	}
}

class GetRemoteStats {
	var $host;
	
	function __construct($host = null) {
		if (is_null($host)) {
			return false;
		} else {
			$this->host = $host;
		}
	}
	function ping() {
		$rdata = array();
		if (mt_rand(1,2) == 1) {
			$ip = '64.85.164.122';
		} else {
			$ip = '64.85.164.123';
		}
		// Ping the host
		if (!exec('ping ' . $this->host . ' -c 5 -i .2 -q -w 3 -I ' . $ip, $output)) {
			return false;
		} foreach ($output as &$line) {
			// Get Loss
			if (preg_match('/([0-9]{1,3})\%\s*?packet\s*?loss/i', $line, $temp) == 1) {
				$rdata['loss'] = $temp[1];
			}
			// Get Latency
			if (preg_match('/([0-9]{1,4}\.[0-9]{1,4})\/([0-9]{1,4}\.[0-9]{1,4})\/([0-9]{1,4}\.[0-9]{1,4})\/([0-9]{1,4}\.[0-9]{1,4})/i', $line, $temp) == 1) {
				$rdata['min'] = $temp[1];
				$rdata['avg'] = $temp[2];
				$rdata['max'] = $temp[3];
				$rdata['mdev'] = $temp[4];
			}
		}
		echo $this->host . ': ' . $rdata['avg'] . '/' . $rdata['loss'] . "% (avg/loss)\n";
		return $rdata;
	}
}

function create_rrd($file, $targets) {
	$options[] = '--step';
	$options[] = 60;
	for ($i = 0; $i != count($targets); $i++) {
		$options[] = 'DS:' . $i . '-loss:GAUGE:600:U:U';
		$options[] = 'DS:' . $i . '-min:GAUGE:600:U:U';
		$options[] = 'DS:' . $i . '-avg:GAUGE:600:U:U';
		$options[] = 'DS:' . $i . '-max:GAUGE:600:U:U';
		$options[] = 'DS:' . $i . '-mdev:GAUGE:600:U:U'
	}
	$options[] = 'RRA:AVERAGE:0.5:1:525960';
	$options[] = 'RRA:MAX:0.5:12:288';
	$options[] = 'RRA:MIN:0.5:12:288';
	$options[] = 'RRA:LAST:0.5:1:1';
	if (!rrd_create($file, $options, count($options))) {
		error_out('Unable to create RRD File!' . "\n" . rrd_error());
	}
}

function update_rrd($file, $input) {
	$data = 'N';
	foreach ($input as $temp) {
		$data .= ':';
		$data .= $temp['loss'] . ':' . $temp['min'] . ':' . $temp['avg']. ':' . $temp['max'] . ':' . $temp['mdev'];
	}
	if (!rrd_update($file, $data)) {
		error_out('Unable to update RRD File!' . "\n" . rrd_error());
	}
}

// Register shutdown function
register_shutdown_function('termination');

// Prevent script timeout
set_time_limit(0);

foreach ($target as $host) {
	$remote_data[] = new GetRemoteStats($host[0]);
}
echo 'Script starting up.' . "\n";

// Loop script indefinitely
while(1) {
	// Check to see if RRD file exists
	if ( !file_exists($file) ) {
		// If RRD file does not exist, create it
		echo 'Creating RRD File...' . "\n";
		create_rrd($file, $target);
	}
	foreach ($remote_data as $data) {
		// Get remote data
		if (!$stats[] = $data->ping()) {
			$stats['loss'] = 100;
			$stats['min'] = 0;
			$stats['avg'] = 0;
			$stats['max'] = 0;
			$stats['mdev'] = 0;
		}
	}
	// Input data into database
	update_rrd($file, $stats);
	// Free Some memory
	unset($stats);
	// Wait 50 Seconds before looping
	sleep(50);
}