<?php
/*
    Copyright (C) 2008  A. Bram Neijt <bram@neijt.nl>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
/*
    This programs creates a small SVG hit counter with graph of the last periods.
    Hit counts are collected per period and for unique hosts/period.
    The period is configurable, see the define statements below.
    Homepage: http://logfish.net/pr/svghitcounter/
    
    Needed tables:
        CREATE TABLE hitcounter_hitcount(periodid INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, `date` DATE NOT NULL, hits INT UNSIGNED NOT NULL, url TEXT NOT NULL);
        CREATE TABLE hitcounter_hitlist(id SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, rhost INT UNSIGNED NOT NULL, period INT UNSIGNED NOT NULL, `date` DATE NOT NULL, UNIQUE(rhost, period));    
*/

require 'SVGElements.php'//Simple class containing SVG code
require 'ip2i.php';    //function to calc unsigned int from ip

function validRef($s)
{
    return 
preg_match('/^https?:\/\/.+/'$s); //Add your domain to make sure you only count your domain
}

//Get data and create hitcounter
$period = (isset($_GET['period']) ? intval($_GET['period']) : 0);//Get period in days from GET
$showTotal = isset($_GET['summate']);

//Maximum period of 1 year
if(! ($period >= && $period <= 365))
    
$period 7;    //Default of 7 days

define('LOGFISH_HITCOUNTER_PERIOD'$period); //$period day periods in graph and counting
define('LOGFISH_HITCOUNTER_PURGE'LOGFISH_HITCOUNTER_PERIOD);    //purge older data
define('LOGFISH_HITCOUNTER_SHOW'8);    //Show 8 periods in graph
define('LOGFISH_HITCOUNTER_WIDTH'200);    
define('LOGFISH_HITCOUNTER_HEIGHT'80);


$lineColor = isset($_GET['line_color']) ? $_GET['line_color'] : 'blue';
$textColor = isset($_GET['text_color']) ? $_GET['text_color'] : 'black';

$hits = array(0);

$referer = isset($_GET['referer']) ? $_GET['referer'] : false;
if(!
validRef($referer))
{
    
//Try to get the ref from HTTP
    
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : false;
}

if(!
validRef($referer))
    
$referer false;

if(
$referer)
{
    
//Clean up referer
    
$referer preg_replace('/index\\.(html|php|htm|rb|py|rhtml)/'''$referer);
    
$referer preg_replace('/^https/''http'$referer);

    require 
'dbh.php'//Creates a PDO database handle in $db, if it fails $db === false
    //If we have both a referer and a db, then we can do our magic and set the counters
    
if($dbh)
    {
        
//Yes, finally let's do some magic
        //Tables needed:
            //CREATE TABLE hitcounter_hitcount(periodid INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, `date` DATE NOT NULL, hits INT UNSIGNED NOT NULL, url TEXT NOT NULL);
            //CREATE TABLE hitcounter_hitlist(id SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, rhost INT UNSIGNED NOT NULL, period INT UNSIGNED NOT NULL, `date` DATE NOT NULL, UNIQUE(rhost, period));
        
        //Get the period id for this period and page
        
$stmt $dbh->prepare('SELECT periodid FROM hitcounter_hitcount WHERE DATE_SUB(CURDATE(), INTERVAL '.LOGFISH_HITCOUNTER_PERIOD.' DAY) < `date` AND url=? LIMIT 1');
        
$stmt->bindParam(1$referer);
        
$stmt->execute();
        
$periodid $stmt->fetch(PDO::FETCH_NUM);
        if(
$periodid)
            
$periodid $periodid[0];
        else
        {
            
//Create new period, nothing matches the current date interval
            
$stmt $dbh->prepare('INSERT INTO hitcounter_hitcount(`date`, hits, url) VALUES(NOW(), 0, ?)');
            
$stmt->bindParam(1$referer);
            if(!
$stmt->execute())
                die(
'Could not insert period, weird internal error here.');
            
$periodid $dbh->lastInsertId();
        }
        
        
//Add hit to ip hitlist
        
$stmt $dbh->prepare('INSERT INTO hitcounter_hitlist(rhost, period, `date`) VALUES(?, ?, NOW())');
        
$stmt->bindParam(1ip2i($_SERVER['REMOTE_ADDR']));
        
$stmt->bindParam(2$periodid);
        if(
$stmt->execute())
        {
            
//Insert OK, we havn't counted this hit yet
            
$stmt $dbh->prepare('UPDATE hitcounter_hitcount SET hits=hits+1 WHERE periodid=? LIMIT 1');
            
$stmt->bindParam(1$periodid);
            
$stmt->execute();
        }
        else
        {
            
//We already counted this host, this period, do nothing, randomly clean up the db
            
if(rand(050))
            {
                
$stmt $dbh->prepare('DELETE FROM hitcounter_hitcount WHERE `date` < DATE_SUB(CURDATE(), INTERVAL ? DAY)');
                
$stmt->bindValue(1LOGFISH_HITCOUNTER_PURGEPDO::PARAM_INT);
                
$stmt->execute();
                
$stmt $dbh->prepare('DELETE FROM hitcounter_hitlist WHERE `date` < DATE_SUB(CURDATE(), INTERVAL ? DAY)');
                
$stmt->bindValue(1LOGFISH_HITCOUNTER_PURGEPDO::PARAM_INT);
                
$stmt->execute();
            }
        }
        
        
//Counting done, now get the graph data
        
$stmt $dbh->prepare(
            
'SELECT hits FROM hitcounter_hitcount WHERE DATE_SUB(CURDATE(), INTERVAL ? DAY) < `date` AND url=? ORDER BY `date` DESC LIMIT ?');
        
$stmt->bindValue(1LOGFISH_HITCOUNTER_PERIOD LOGFISH_HITCOUNTER_SHOWPDO::PARAM_INT);
        
$stmt->bindParam(2$referer);
        
$stmt->bindValue(3LOGFISH_HITCOUNTER_SHOWPDO::PARAM_INT);
        if(!
$stmt->execute())
        {
            
print_r($stmt);
            
print_r($stmt->errorInfo());
            die(
'Get data failure');
        }
        
$hits $stmt->fetchAll(PDO::FETCH_COLUMN);
        
$stmt null;
    }
}

//Start of output section
//Create SVG hitcounter if we have hits
$dx LOGFISH_HITCOUNTER_WIDTH LOGFISH_HITCOUNTER_SHOW;
$max $hits[0];
$total 0;
foreach(
$hits as $hit)
    if(
$hit $max)
        
$max $hit;
$scale $max doubleval(LOGFISH_HITCOUNTER_HEIGHT) / $max 1;

$path 'M 0 '.LOGFISH_HITCOUNTER_HEIGHT;
$lastHit 0;
foreach(
$hits as $hit)
{
    
$dy = ($lastHit $hit) * $scale;
    
$path .= " l $dx $dy";
    
$lastHit $hit;
    
$total += $hit;
}
$path .= ' L '.LOGFISH_HITCOUNTER_WIDTH.' '.LOGFISH_HITCOUNTER_HEIGHT.' z';
$hitcounter SVGElements::path($path$lineColor);

$hitcounter .= SVGElements::link(SVGElements::text(($showTotal $total $hits[0]), $textColorround(LOGFISH_HITCOUNTER_HEIGHT/1.3), 'start', array('x' => 0'y' => round(LOGFISH_HITCOUNTER_HEIGHT/1.1))), 'http://logfish.net/pr/svghitcounter');

header('Content-type: image/svg+xml');
echo 
'<?xml version="1.0" standalone="no"?>';

?>

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg viewBox="0 0 <?php echo LOGFISH_HITCOUNTER_WIDTH.' '.LOGFISH_HITCOUNTER_HEIGHT ?>" version="1.1"
     xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <desc>Logfish.net hit counter with <?php echo LOGFISH_HITCOUNTER_PERIOD ?> day graph for <?php echo htmlentities($referer); ?></desc>
<?php echo $hitcounter ?>
</svg>