<?php    ### linkcounter.php ###

$filename = '.ht_clickcounter.txt';

## Zur Installation Kommentarzeichen entfernen
# touch($filename)

define('IP_BLOCKINGTIME', 10);  ## Blockintime 1 Hour

### ----------------------------------------------------

function link_count_click($filename, $respect_forwarded = true, $respect_querystring = false)
{

    if (!defined('IP_BLOCKINGTIME'))
    {
        define('IP_BLOCKINGTIME', 3600);  ## Blockintime 1 Hour as default
    }

    $ip = $_SERVER['REMOTE_ADDR'];
    $link = strtolower($_SERVER['HTTP_HOST']) . $_SERVER['SCRIPT_NAME'];

    ## ggf. noch ergänzen um den Query-String
    
    if ($respect_querystring)
    {
        if (isset($_SERVER['QUERY_STRING']) and strlen($_SERVER['QUERY_STRING']) > 0)
        {
            $link .= '?'. $_SERVER['QUERY_STRING'];
        }
    }

    ## eventuell X_FORWARDED_FOR berücksichtigen
    if ($respect_forwarded)
    {
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
        {
            $ip .= ';' . $_SERVER['HTTP_X_FORWARDED_FOR'];
        }
    }    

    $time = time();

    ### ----------------------------------------------------

    ## Aufbau eines Records, $link ist 1. Index, $ip ist 2. Index
    #$_linklist = array();
    #$_linklist[$link] = array();
    #$_linklist[$link][$ip] = array();
    #$_linklist[$link][$ip]['lasttime'] = 0;
    #$_linklist[$link][$ip]['clicks'] = 0;

    ## Daten holen

    $fh = @fopen($filename, 'rb+');
    if (!$fh) return false;
    if (!flock($fh, LOCK_EX))
    {
        fclose($fh);
        return false; 
    }    

    clearstatcache();
    $stream = fread($fh, (filesize($filename) + 1));

    if (strlen($stream) == 0)
    {
        $_linklist = array();
    }
    else
    {
        $_linklist = unserialize($stream);
    }    
    unset($stream);

    if (!is_array($_linklist)) 
    {
        fclose($fh);
        return false;
    }    


    ## Ist der Link bereits in der Liste?
    if (isset ($_linklist[$link]))
    {
        ## Ist der Link schon von der IP aufgerufen worden?
        if (isset ($_linklist[$link][$ip]))
        {
            ## Wie lange ist es her, dass der Link aufgerufen wurde?
            if ($time - $_linklist[$link][$ip]['lasttime'] > IP_BLOCKINGTIME )
            {
                ## Aufrufzähler hochzählen und Aufrufzeit nachtriggern            
                $_linklist[$link][$ip]['clicks'] ++;
                $_linklist[$link][$ip]['lasttime'] = $time;
            }
            else
            {
                ## Nur Letzte Aufrufzeit nachtriggern
                $_linklist[$link][$ip]['lasttime'] = $time;
            }
        }
        else
        {
            ## Neue IP für den Link eintragen, 
            ## letzte Aufrufzeit setzen und 
            ## Klickzähler hochsetzen
            $_linklist[$link][$ip] = array();
            $_linklist[$link][$ip]['lasttime'] = $time;
            $_linklist[$link][$ip]['clicks'] = 1;
        }
    }
    else
    {
        ## Datensatz für Link komplett neu anlegen
        $_linklist[$link] = array();
        $_linklist[$link][$ip] = array();
        $_linklist[$link][$ip]['lasttime'] = $time;
        $_linklist[$link][$ip]['clicks'] = 1;
    }

    ## Array serialaisieren
    $stream = serialize ($_linklist);

    ## Daten wegschreiben
    fseek($fh, 0, SEEK_SET);
    fwrite($fh, $stream);
    ftruncate($fh, strlen($stream));
    fclose($fh);

    return $_linklist[$link][$ip]['clicks'];
}

#-----------------------------------------------------------------------------------

function link_get_click_list($filename)
{
    $fh = @fopen($filename, 'rb');
    if (!$fh) return false;
    if (!flock($fh, LOCK_SH)) 
    {
        flcose($fh);
        return false;
    }    

    clearstatcache();  ## muss vor jedem Aufruf von filesize() aufgerufen werden,
                       ## wenn man den aktuellen Wert im Thread haben will. 
    $stream = fread($fh, (filesize($filename) + 1));

    $_linklist = unserialize($stream);
    unset($stream);

    ### hat unserialize() geklappt?
    if (!is_array($_linklist)) 
    {
        fclose($fh);
        return false;
    }    

    ### Ist in der Datei ein passendes Format vorhanden gewesen?
    if (!isset($_linklist[key($_linklist)][key($_linklist[key($_linklist)])]['clicks'], 
               $_linklist[key($_linklist)][key($_linklist[key($_linklist)])]['lasttime']))
    {
        fclose($fh);
        return false;
    }    

    fclose($fh);

    return $_linklist;
}
#-----------------------------------------------------------------------------------

function link_get_all_clicks ($_clicklist, $link, $ip=false)
{
    ## Format von $_clicklist muss geprüft sein!

    ## Gibt die Klicks zu einer bestimmten IP eines Links zurück.
    ## Wenn $ip === false ist, werden alle Klicks über 
    ## alle IPs aufsummiert für den Link

    if (!isset($_clicklist[$link])) return 0;

    if($ip !== false)
    {
        if (!isset($_clicklist[$link][$ip])) return 0;
        return $_clicklist[$link][$ip]['clicks'];
    }
    
    $clicks = 0;
    foreach ($_clicklist[$link] as $ip => $info)
    {
        $clicks += $info['clicks'];
    }

    return $clicks;
}

#-----------------------------------------------------------------------------------

function link_get_last_time ($_clicklist, $link, $ip=false)
{
    ## Format von $_clicklist muss geprüft sein!

    ## Gibt den timestamp des letzten Zugriffs einer bestimmten IP eines Links zurück.
    ## Wenn $ip === false ist, wird der letzte Zugriff auf den Link festgestellt,
    ## unabhängig von der IP

    if (!isset($_clicklist[$link])) return false;

    if($ip !== false)
    {
        if (!isset($_clicklist[$link][$ip])) return false;
        return $_clicklist[$link][$ip]['lasttime'];
    }
    
    $lasttime = 0;
    foreach ($_clicklist[$link] as $ip => $info)
    {
        $lasttime = max($lasttime, $info['lasttime']);
    }

    return $lasttime;
}

#-----------------------------------------------------------------------------------

function link_get_last_ip ($_clicklist, $link)
{
    ## Format von $_clicklist muss geprüft sein!

    ## Gibt die IP zurück, von der aus der letzte Zugriff 
    ## auf den Link vorgenommen wurde

    if (false === ($lasttime = link_get_last_time($_clicklist, $link))) return false;

    foreach ($_clicklist[$link] as $ip => $info)
    {
        if ($lasttime == $info['lasttime']) return $ip;
    }

    return $false;
}


#===================================================================================
#   PHP main
#===================================================================================


$count = link_count_click($filename, true, true);

echo "<pre>\r\n";

echo "Clicks aktuelle Seite: ", var_dump($count);

echo "Block-Time: ", var_dump(IP_BLOCKINGTIME);

$_clicklist = link_get_click_list($filename);

var_dump($_clicklist);

$clicks = link_get_all_clicks($_clicklist, 'localhost/counter/linkcounter.php?zwei');
$lasttime = date('Y-m-d H:i:s', link_get_last_time($_clicklist, 'localhost/counter/linkcounter.php?zwei', '127.0.0.1'));
$lastip = link_get_last_ip($_clicklist, 'localhost/counter/linkcounter.php?zwei'); 

echo "<u>localhost/counter/linkcounter.php?zwei</u>: ", $clicks, ' Zugriffe, ', $lasttime, ', ',$lastip;

echo "</pre>\r\n";

?>