<?php
	/**************************************************************************
	 * mrtgtu - MRTG Traffic Utilization. 
	 * Analyzes MRTG log files and determines the total traffic used.
	 * Copyright (C) 2011 S. McAvoy <steve@smis.ca>
	 *
	 * 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 3 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.
	 * You should have received a copy of the GNU General Public License
	 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
	 *
	 * @author S. McAvoy <steve@smis.ca>
	 * @package mrtgtu
	 * @copyright 2011
	 * @version 0.9.1b
	 *
	 * Installation
	 * --------------------
	 *
	 * Just edit the LOG_DIR constant below and place this script and the
	 * accompanying style.css files in a directory that is accessible by your
	 * http server.
	 *
	 **************************************************************************/
	define('LOG_DIR', '../MRTG/');


	/***************************************************************************
	 * No need to edit anything below this line unless you want to hack. */

	define('VERSION', '0.9.1b');
	define('PACKAGE_NAME', 'mrtgtu');


	/**
	 * Scales the number of bytes into kilo, mega, giga, etc.
	 * @param int $num The number of bits or bytes to scale.
	 * @param string $suffix
	 * @param bool $metric If true, results will be scaled in base 10 insted of
	 *                 base 2.
	 * @param int $precision The number of decimal places to keep.
	 * @return string Number of bytes scaled in appropriate units (eg. M G).
	 */
	function auto_scale($num, $suffix, $metric=false, $precision=2)
	{
		$unit_map = array("K", "M", "G", "T", "E");
		$unit = 0;
		$denominator = ($metric) ? 1000.0 : 1024.0;

		while (($num /= $denominator) > $denominator)
			$unit++;

		return round($num, $precision) . ' ' . $unit_map[$unit] . $suffix;
	}



	/**
	 * Converts bytes to bits.
	 * @param int $bytes The number of bytes to convert to bits.
	 * @return int The number of bits in the given bytes.
	 */
	function to_bits($bytes)
	{
		return $bytes * 8;
	}



	/**
	 * Retrieves the names of the log files from the given directory.
	 * @param string $dir the director containing MRTG log files.
	 * @return array absolute path names for MRTG log files which were found.
	 */
	function get_log_filenames($dir)
	{
		$file = '';
		$files = array();

		if (!is_dir($dir))
			exit("The directory '$dir' does not exist.");

		$h = opendir($dir);
		if (!$h)
			exit("Unable to open directory '$dir'.");

		while ($file = readdir($h))
			if (preg_match('/\.log$/', $file))
				$files[] = $dir . '/' . $file;

		closedir($h);

		sort($files, SORT_STRING);

		return $files;
	}



	/**
	 * Parses an MRTG log file and extracts the relevant sections.
	 * @param int $time_start The UNIX timestamp to start from.
	 * @param int $time_stop The UNIX timestamp to stop at.
	 * @return array 
	 */
	function parse_log_file($time_start, $time_stop, $filename)
	{
		$results = array();
		$fd = fopen($filename, "r");

		if (!$fd)
			exit("Unable to open log file '$filename'.");

		while (!feof($fd))
		{
			$line = fgets($fd);
			$cols = explode(" ", $line);

			// We only want the relevant sections in the log file.
			if ($cols[0] >= $time_start && $cols[0] <= $time_stop)
				$results[] = $cols;
		}

		fclose($fd);

		return $results;
	}



	/**
	 * Parses an array of results generated by <pre>parse_log_file</pre>.
	 * @param int $bytes_in  The variable to store the amount of ingress traffic.
	 * @param int $bytes_out The variable to store the amount of egress traffic.
	 * @param array $results An array generated by <pre>parse_log_file</pre>.
	 */
	function parse_results(&$bytes_in, &$bytes_out, $results)
	{
		$t = 0;
		$dt = 0;
		$prev_time = 0;

		$bytes_in = 0;
		$bytes_out = 0;

		for ($i=count($results)-1; $i>=0; $i--)
		{
			if ($i == count($results)-1)
			{
				$prev_time = $results[$i][0];
			}
			else
			{
				$t = $results[$i][0];
				$dt = $t - $prev_time;
				$bytes_in += $dt * $results[$i][1];
				$bytes_out += $dt * $results[$i][2];
				$prev_time = $t;
			}
		}
	}



	/**
	 * Creates a UNIX timestamp for a given year, month, and day.
	 * The day is assumed to start at 00:00:00 hours.
	 * @param int $year
	 * @param int $month
	 * @param int $day
	 * @return int A UNIX timestamp.
	 */
	function mktime_start($year, $month, $day)
	{
		return strtotime($year.'-'.$month.'-'.$day.' 00:00:00');
	}



	/**
	 * Creates a UNIX timestamp for a given year, month, and day.
	 * The day is assumed to end at 23:59:59 hours.
	 * @param int $year
	 * @param int $month
	 * @param int $day
	 * @return int A UNIX timestamp.
	 */
	function mktime_stop($year, $month, $day)
	{
		return strtotime($year.'-'.$month.'-'.$day.' 23:59:59');
	}



	/**
	 * Outputs an HTML table containing traffic data for a given MRTG log file.
	 * @param int $time_start The UNIX timestamp of the start time.
	 * @param int $time_stop The UNIX timestamp of the end time.
	 * @param string $logfile The absolute path of the MRTG log to analyze.
	 * @css_id int A unique numeric value to append to the DIV's ID property.
	 */
	function prt_traffic($time_start, $time_stop, $logfile, $css_id)
	{
		$dt = $time_stop - $time_start;
		$bytes_in = 0;
		$bytes_out = 0;
		$bits_in = 0;
		$bits_out = 0;
		$hostname = '';
		$ip = '';
		$results = null;

		// Parse the logfile and determine total traffic consumed.
		$results = parse_log_file($time_start, $time_stop, $logfile);
		parse_results($bytes_in, $bytes_out, $results);

		// Convert bytes to bits
		$bits_in = to_bits($bytes_in);
		$bits_out = to_bits($bytes_out);

		// Print the traffic table for this host.
		print('<div id="tt_'.$css_id.'" class="traffic_table">'."\n".
				'<div class="header">' . "\n" .
					'<div>File: <span class="filename">' . basename($logfile) . '</span></div>' . "\n" .
				'</div>' . "\n" .
				'<table>' . "\n" .
				'<tr>' . "\n" .
					'<th colspan="4">Ingress Traffic</th>' . "\n" .
					'<th class="in_out_spacer">&nbsp;</th>' . "\n" .
					'<th colspan="4">Egress Traffic</th>' . "\n" .
				'</tr>' . "\n" .
				'<tr>' . "\n" .
					'<th class="ingress">Bits In</th>' . "\n" .
					'<th class="ingress">Avg. Bits In</th>' . "\n" .
					'<th class="ingress">Bytes In</th>' . "\n" .
					'<th class="ingress">Avg. Bytes In</th>' . "\n" .
					'<th class="in_out_spacer">&nbsp;</th>' . "\n" .
					'<th class="egress">Bits Out</th>' . "\n" .
					'<th class="egress">Avg. Bits Out</th>' . "\n" .
					'<th class="egress">Bytes Out</th>' . "\n" .
					'<th class="egress">Avg. Bytes Out</th>' . "\n" .
				'</tr>' . "\n" .
				'<tr>' . "\n" .
					'<td class="ingress">' . auto_scale($bits_in, 'b') . '</td>' . "\n" .
					'<td class="ingress">' . auto_scale($bits_in/$dt, 'b/s') . '</td>' . "\n". 
					'<td class="ingress">' . auto_scale($bytes_in, 'B') . '</td>' . "\n" .
					'<td class="ingress">' . auto_scale($bytes_in/$dt, 'b/s') . '</td>' . "\n". 
					'<td class="in_out_spacer">&nbsp;</td>' . "\n" .
					'<td class="egress">' . auto_scale($bits_out, 'b') . '</td>' . "\n" .
					'<td class="egress">' . auto_scale($bits_out/$dt, 'b/s') . '</td>' . "\n" .
					'<td class="egress">' . auto_scale($bytes_out, 'B') . '</td>' . "\n" .
					'<td class="egress">' . auto_scale($bytes_out/$dt, 'B/s') . '</td>' . "\n" .
				'</tr>' . "\n" .
				'</table>' . "\n" .
			'</div>'."\n");
	}

	function clean_date_input($date)
	{
		return preg_replace('/[^0-9]/', '', $date);
	}

	/********************************
	 * Process the form data
	 */
	$_now = time();
	$input = array();

	// If the form has been submitted, grab the date components
	// otherwise use default values.
	if (isset($_GET['_submit']) && $_GET['_submit'] == 1)
	{
		$input['start_year'] = clean_date_input($_GET['start_year']);
		$input['start_month'] = clean_date_input($_GET['start_month']);
		$input['start_date'] = clean_date_input($_GET['start_date']);
		$input['stop_year'] = clean_date_input($_GET['stop_year']);
		$input['stop_month'] = clean_date_input($_GET['stop_month']);
		$input['stop_date'] = clean_date_input($_GET['stop_date']);
	}
	else
	{
		// Use the current month for default values if the page
		// is loaded without populated parameters.
		$input['start_year'] = date('Y', $_now);
		$input['start_month'] = date('m', $_now);
		$input['start_date'] = '01';
		$input['stop_year'] = date('Y', $_now);
		$input['stop_month'] = date('m', $_now);
		$input['stop_date'] = date('t', $_now);  // Last day of current month.

	}

	// Create the start and stop timestamps that we'll use when scanning
	// throught the MRTG log files.
	$start_time = mktime_start($input['start_year'], $input['start_month'], $input['start_date']);
	$stop_time = mktime_stop($input['stop_year'], $input['stop_month'], $input['stop_date']);

	// Set a friendly date format to be used in the page title.
	$start_title = date('Y-m-d H:i:s', $start_time);
	$stop_title = date('Y-m-d H:i:s', $stop_time);
?>
<?php print('<?xml version="1.0" encoding="UTF-8"?>'."\n"); ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
	<title>Total Bandwidth Consumption from <?php print($start_title . ' until ' . $stop_title); ?></title>
	<link rel="stylesheet" type="text/css" media="screen" href="style.css" />
	<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
	<meta name="author" content="S. McAvoy" />
	<meta name="description" content="Report for traffic utilization using existing MRTG log files." />

	<!-- Consider better protection against search engine indexing than this simple meta tag. -->
	<meta name="googlebot" content="noindex" />
</head>
<body>
	<div id="head-block">
		<h1 id="title">MRTG Traffic Utilization <span class="version">v<?php print(VERSION); ?></span></h1>
		<div id="dates">
			<form id="frm-date" action="<?php print($_SERVER['PHP_SELF']); ?>" method="get">
				<table>
					<tr>
						<td>From:
						   <input type="text" name="start_year" size="4" value="<?php print($input['start_year']); ?>" /> -
							<input type="text" name="start_month" size="2" value="<?php print($input['start_month']); ?>" /> -
							<input type="text" name="start_date" size="2" value="<?php print($input['start_date']); ?>" />
						</td>
						<td>To:
						   <input type="text" name="stop_year" size="4" value="<?php print($input['stop_year']); ?>" /> -
							<input type="text" name="stop_month" size="2" value="<?php print($input['stop_month']); ?>" /> -
							<input type="text" name="stop_date" size="2" value="<?php print($input['stop_date']); ?>" />
						</td>
						<td>
							<input type="hidden" name="_submit" value="1" />
							<input type="submit" value="Generate Report" />
							<span class="smalltext">Enter dates as: <em>yyyy-mm-dd</em></span>
						</td>
					</tr>
				</table>
			</form>
		</div>
	</div>
	<div id="data">
	<p>Report for <strong><?php echo date('F', $start_time) . ' ' . date('j', $start_time) . ', ' . date('Y', $start_time); ?></strong> to <strong><?echo date('F', $stop_time) . ' ' . date('j', $stop_time) . ', ' . date('Y', $stop_time); ?></strong>.</p>
	<?php

		// Get the log files to be analyzed.
		$logfiles = get_log_filenames(LOG_DIR);

		if (count($logfiles))
		{
			// This value incrememts for each log file. Its value is appended
			// to the CCS 'id' property of every log file's DIV block.
			$css_id = 0;

			// For each log file, print the traffic utilization for
			// the given period.
			foreach ($logfiles as $log)
				prt_traffic($start_time, $stop_time, $log, $css_id++);
		}
		else
		{
			// No log files were found.
			print("<div class=\"error\">No log files were found. Have you configured the LOG_DIR value?</div>\n");
		}
	?>
	</div>
</body>
</html>
