<?php
error_reporting(E_NOTICE);
/*

==============================================================================

    SAIX Live Userstats Script

==============================================================================

    This script will insert your current connection statistics into SAIX's
     'ADSL User Statistics' page.  This is useful if you want to display
     real time statistics in utilities such as Minimeter.

==============================================================================

<VirtualHost *>
    DocumentRoot /var/www/html/userstats/
    ServerName userstats.adsl.saix.net
    ErrorLog logs/userstats.adsl.saix.net-error_log
    CustomLog logs/userstats.adsl.saix.net-access_log common
    Alias /icons/ "/var/www/html/userstats/icons/"
</VirtualHost>

AddType image/vnd.microsoft.icon .ico

<Directory "/var/www/html/userstats">
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-l
    RewriteRule . /userstats.php [L]
    RewriteRule ^$ /userstats.php [L]
</Directory>

*/

$ppp_interface = 'ppp0';
$ppp_pid_file = '/var/run/pppoe-adsl.pid.pppd';

$host = "userstats.adsl.saix.net";
$path = $_SERVER["REQUEST_URI"];

$fp = fsockopen($host, 80, $errno, $errstr, 30);

if (!$fp) {
    echo "$errstr ($errno)\n";
} else {

    if (($path == "/") || ($path == "/perl/") || (substr($path, 0, 7) == "/perl/?") || (substr($path, 0, 14) == "/perl/index.pl"))
    {
        $sysuptime = file('/proc/uptime');
        $sysuptime = explode(" ", $sysuptime[0]);

        $pppdpid = file($ppp_pid_file);
        $pppdstat = file('/proc/'.trim($pppdpid[0]).'/stat');
        $pppdstat = explode(" ", $pppdstat[0]);

        if (count($pppdstat) > 20)
        {
            $pppduptime = $pppdstat[21];
            $pppdage = (int)$sysuptime[0] - (int)($pppduptime / 100);
        }
        else
        {
            $pppdage = 0;
        }

        $pppstart = time() - $pppdage;
        $today = mktime(0, 5, 0);
        if ($pppstart < $today)
        {
            $pppstart = $today;
            $pppdage = time() - $today;
        }

        $request = strstr($path, '?');
        $thismonth = date('\?\Y\E\A\R\=Y\;\M\O\N\T\H\=m', $pppstart);
        if ($request == '')
        {
            $request = $thismonth;
            $path = "/perl/index.pl" . $request;
        }
    }

    $auth = Null;
    $auth_username = Null;
    foreach (apache_request_headers() as $header => $value)
    {
        if ($header == "Authorization")
        {
            $auth = explode(' ', $value);
            $auth = $auth[1];
        }
    }
    if ($auth != Null)
    {
        $auth = explode(':', base64_decode($auth));
        $auth_username = $auth[0];
    }

    $allow_auth = 1;
    if (substr($path, 0, 15) == "/perl/logout.pl")
    {
        $allow_auth = 0;
        $request = strstr($path, '?');
        if ($request != '?id='.$auth_username)
        {
            header("Location: /");
            exit();
        }
        else
        {
            $path = '/';
        }
    }

    $out = "GET $path HTTP/1.0\r\n";
    $out .= "Host: $host\r\n";

    foreach (apache_request_headers() as $header => $value)
    {
        if (($header != "Host") && ($header != "Connection") && (($header != "Authorization") || ($allow_auth == 1))) {
            $out .= "$header: $value\r\n";
        }
    }

    $out .= "\r\n";

    fwrite($fp, $out);

    $buffer = '';
    while (!feof($fp)) {
        $buffer .= fgets($fp, 128);
    }

    fclose($fp);

    $headers = substr($buffer, 0, strpos($buffer, "\r\n\r\n"));
    $buffer = substr($buffer, strpos($buffer, "\r\n\r\n") + 4);

    foreach (explode("\r\n", $headers) as $header)
    {
        header($header);
    }

    if (($path == "/") || (substr($path, 0, 6) == "/perl/"))
    {
        $rows = 0;
        if ((substr($path, 0, 7) == "/perl/?") || (substr($path, 0, 14) == "/perl/index.pl"))
        {
            if ($request == $thismonth)
            {
                $pppstats = explode("\n", `/usr/sbin/pppstats $ppp_interface 2>&1`);
                $pppstats = preg_split("/ +/", trim($pppstats[1]));

                $basestats = explode("\n", `/bin/cat /var/run/$ppp_interface.pppstats 2>&1`);
                $basestats = preg_split("/ +/", trim($basestats[1]));

                if ((count($pppstats) > 6) && (count($basestats) > 6))
                {
                    $pppin = $pppstats[0] - $basestats[0];
                    $pppout = $pppstats[6] - $basestats[6];

                    $pattern = "/<th>Combined \(Bytes\)<\/th><tr><td>([0-9\.]*+)<\/td><td>([0-9]*+)<\/td><td>([0-9 ]*+)<\/td><td>([0-9 ]*+)<\/td><td>([0-9 ]*+)<\/td>/";

                    $buffer = preg_replace_callback($pattern, "replace_numbers", $buffer);
                }
            }

            $links  = '<li><a href="/perl/logout.pl?id='.$auth_username.'">Logout</a></li>';
            $buffer = preg_replace("#</ul>#", $links . "\\0", $buffer);

            $buffer = preg_replace_callback("#Daily.*</table>#", "add_session_table_bars", $buffer);
            $days = $rows;
            $rows = -3;
            $buffer = preg_replace_callback("#Cumulative.*</table>#", "add_session_table_bars", $buffer);
        }
        else if ((substr($path, 0, 16) == "/perl/history.pl") || (substr($path, 0, 18) == "/perl/sessions.pl?"))
        {
            $buffer = preg_replace_callback("#<table.*</table>#", "add_history_table_bars", $buffer);
        }

        $buffer = preg_replace("#(href=)(/[^>]*+)#", "\\1'\\2'", $buffer); # HTML Validation Fix
        $buffer = preg_replace("#&[lg]t(?!;)#", "\\0;", $buffer); # HTML Validation Fix
        $buffer = str_replace('</div></body></html></div>', '</div></div></body></html>', $buffer); # HTML Validation Fix
    }

    echo $buffer;
}

function add_session_table_bars($matches)
{
    $data = $matches[0];
    $data = preg_replace("#(?<!<tr>|</th>)<th>.*</th>#", "<tr>\\0</tr>", $data); # HTML Validation Fix
    return preg_replace_callback("#(<td>(.[^<]*+)</td><td>(.[^<]*+)</td><td>.[^<]*+</td>)(</tr>)#", "add_session_row_bars", $data);
}

function add_session_row_bars($matches)
{
    return $matches[1] . make_row_bars(str_replace(' ', '', $matches[2]), str_replace(' ', '', $matches[3])) . $matches[4] . "\n";
}

function add_history_table_bars($matches)
{
    global $days, $rows, $histories, $histid;
    $histories = array();
    $histid = 'a';
    $details = preg_replace_callback("#(<td[^>]*+>(.[^<]*+)</td><td[^>]*+>(.[^<]*+)</td><td[^>]*+>(.[^<]*+)</td><td[^>]*+>(.[^<]*+)</td><td[^>]*+>(.[^<]*+)</td>)(</tr>)#", "add_history_row_bars", $matches[0]);
    $summary = "<table cellspacing='1'><tr><th>ID</th><th>Sessions</th><th>Online Time (Seconds)</th><th>Upload (Bytes)</th><th>Download (Bytes)</th><th>Combined (Bytes)</th></tr>";
    $duration = 0;
    foreach ($histories as $history)
    {
        $summary .=
            "<tr><td>" . $history['id'] .
            "</td><td title='". join(",\n",$history['ips']) . "'>" . $history['rows'] .
            "</td><td>" . $history['duration'] .
            "</td><td>" . number_format($history['upload'], 0, '.', ' ') .
            "</td><td>" . number_format($history['download'], 0, '.', ' ') .
            "</td><td>" . number_format($history['upload'] + $history['download'], 0, '.', ' ') .
            "</td></tr>";
        $duration += $history['duration'];
    }
    $summary .= "</table>";
    $days = $duration / 129600 / count($histories);
    $rows = -count($histories)-1;
    $summary = preg_replace_callback("#(<td>(.[^<]*+)</td><td>(.[^<]*+)</td><td>.[^<]*+</td>)(</tr>)#", "add_session_row_bars", $summary);
    return "<h3>Summary:</h3>".$summary."<h3>Details:</h3>".$details;
}

function add_history_row_bars($matches)
{
    global $rows,$histories,$histid;
    $end = strtotime($matches[2]);
    $duration = $matches[3];
    $start = $end - $duration;
    $ip = $matches[4];
    $upload = str_replace(' ', '', $matches[5]);
    $download = str_replace(' ', '', $matches[6]);

    $foundkey = Null;
    foreach ($histories as $key=>$history)
    {
        if ($history['lastip'] == $ip)
        {
            $foundkey = $key;
            break;
        }
    }
    if ($foundkey === Null)
    {
        foreach ($histories as $key=>$history)
        {
            if (($start > $history['end']) && (substr($history['lastip'], 0, strpos($history['lastip'], '.', strpos($history['lastip'], '.') + 1)) == substr($ip, 0, strpos($ip, '.', strpos($ip, '.') + 1))))
            {
                $foundkey = $key;
                break;
            }
        }
    }
    if ($foundkey === Null)
    {
        foreach ($histories as $key=>$history)
        {
            if ((($start + 420) > $history['end']) && (substr($history['lastip'], 0, strpos($history['lastip'], '.', strpos($history['lastip'], '.') + 1)) == substr($ip, 0, strpos($ip, '.', strpos($ip, '.') + 1))))
            {
                $foundkey = $key;
                break;
            }
        }
    }
    if ($foundkey === Null)
    {
        $histories[] = array('id'=>$histid,'ips'=>array(),'rows'=>0,'duration'=>0,'upload'=>0,'download'=>0);
        $histid++;
        end($histories);
        $foundkey = key($histories);
    }
    $history = $histories[$foundkey];
    $history['end'] = $end;
    $history['lastip'] = $ip;
    if (!in_array($ip, $history['ips'])) $history['ips'][] = $ip;
    $history['rows'] += 1;
    $history['duration'] += $duration;
    $history['upload'] += $upload;
    $history['download'] += $download;
    $histories[$foundkey] = $history;
    return $matches[1] . "<td>".$history['id']."</td>" . make_row_bars($upload, $download) . $matches[7] . "\n";
}

function make_row_bars($upload, $download)
{
    global $rows, $days;
    $rows++;
    $factor = 25000000;
    if ($rows < 0 && $days > 0) $factor *= $days;
    $td = "<td style='text-align:left'>";
    $td .= "<img style='width: " . round($upload / $factor, 2) . "em; height: 1.2em;' src='/icons/green.gif' alt='upload'/>";
    $td .= "<img style='width: " . round($download / $factor, 2) . "em; height: 1.2em;' src='/icons/blue.gif' alt='download'/>";
    $td .= "</td>";
    return $td;
}

function replace_numbers($matches)
{
    global $pppdage, $pppout, $pppin;
    $data = preg_replace_callback("/<td>([0-9 ]*+)<\/td>/", "replace_number", $matches[0]);
    $data .= '</tr><tr>';
    $data .= strstr($matches[0], '<td');
    $data .= '</tr><tr>';
    $data .= '<td>today</td>';
    $data .= '<td>'.$pppdage.'</td>';
    $data .= '<td>'.fmt($pppout).'</td>';
    $data .= '<td>'.fmt($pppin).'</td>';
    $data .= '<td>'.fmt($pppout+$pppin).'</td>';
    return $data;
}

function replace_number($matches)
{
    global $tagindex, $pppdage, $pppout, $pppin;
    $tagindex++;
    $val = str_replace(' ', '', $matches[1]);
    switch ($tagindex) {
    case 1: // Sessions
        $val = number_format($val + $pppdage / 86400,2,'.','');
        break;
    case 2: // Online Time (Seconds)
        $val = $val + $pppdage;
        break;
    case 3: // Upload (Bytes)
        $val = $val + $pppout;
        break;
    case 4: // Download (Bytes)
        $val = $val + $pppin;
        break;
    case 5: // Combined (Bytes)
        $val = $val + $pppout + $pppin;
        break;
    }
    if ($tagindex < 3)
    {
        return "<td>".$val."</td>";
    }
    else
    {
        return "<td>".fmt($val)."</td>";
    }
}

function fmt($number)
{
    return number_format($number, 0, '.', ' ');
}

?>