<?php

/**
 * Tail
 *
 * liesst eine Datei Zeilenweise aus 
 * und wartet auf aenderungen.
 *
 * @author   Aron Schlesinger <as@paefchen.net>
 * @version  1.0
 * @license  BSDL
 * @php      5
 **/

class Tail {

    private 
$fh;
    private 
$file;
    private 
$linelength;
    private 
$error '';

    
    
/**
     * __construct
     *
     * constructer, pruefft ob die Datei lesbar ist und setzt
     * oefnet die Datei und setzt den Zeiger an die richtige stelle.
     *
     * @public
     *
     * @para    file        string  Datei die gelesen werden soll
     * @para    lines       int     Zeilen die vom ende gelsen werden sollen.
     * @para    linelength  int     Max. laenge einer Zeile
     **/
    
public function __construct($file$lines 5$linelength 1014) {
        
$this->open($file);
        if (! 
$this->error())
            
$this->setLine($lines);
        
$this->linelength = (int)$linelength;
    }

    
    
/**
     * __destruct
     *
     * destructer, schliesst die Datei
     *
     * @public
     **/
    
public function __destruct() {
        @
fclose($this->fh);
    }


    
/**
     * line
     *
     * liesst und wartet auf Zeilen
     *
     * @public
     * @return    string    zeile
     **/
    
public function line() {
        if (
$this->error())
            return 
false;

        
$line '';
        while (
true) {
            
clearstatcache();
            if (
ftell($this->fh) == filesize($this->file))
                
sleep(1);
            else { 
                
$c fgetc($this->fh);
                if (
strlen($line) <= $this->linelength)
                    
$line .= $c;
                if (
$c == "\n")
                    break;
            }
        }
        return 
$line;
    }


    
/**
     * open
     *
     * oeffnet eine Datei
     *
     * @private
     * @para    file    string   Datei die geoeffnet werden soll.
     * @return  bool
     **/
    
private function open($file) {
        if (! 
is_readable($file)) {
            
$this->error sprintf('File %s not readable'$file);
            return 
false;
        }

        
$this->fh = @fopen($file'r');
        if (! 
$this->fh) {
            
$this->error sprintf('fopen() make error on file %s'$file);
            return 
false;
        }

        
$this->file $file;
    }


    
/**
     * setLine
     *
     * setzt den Zeiger vom ende aus gesehen 
     * auf dem anfang der gewuenschte Zeile 
     *
     * @private
     * @para    line    int      Zeile von hinten aus
     * @return  bool
     **/
    
private function setLine($line) {
        
fseek($this->fh, -1SEEK_END);
        
$p ftell($this->fh);
        
        while (
$line 0) {
            if (
$p === 0)
                break;
            
fseek($this->fh, --$pSEEK_SET);
            if (
fgetc($this->fh) == "\n")
                
$line--;
        }
    }


    
/**
     * go
     *
     * @public
     **/
    
public function go() {
         if (
$this->error())
             return 
false;

        if (isset(
$_SERVER['REQUEST_METHOD'])) {
            
set_time_limit(0);
            
header('Content-type: text/plain');
            
header('Cache-Control: no-store, no-cache');
        }
        
        
ob_implicit_flush(1);

        while (
$line $this->line()) {
            if (isset(
$_SERVER['REQUEST_METHOD']) 
            && 
connection_status() > 0)
                exit;

            print 
$line;
        }
    }


    
/* Error Methods */
    
public function error() { return empty($this->error) ? false true; }
    public function 
getError() { return $this->error; }
}


# Tail object erstellen.
$tail = new Tail('/var/log/vhost/paefchen.net/www-access.log'201024);
$tail->go();
if (
$tail->error())
    die(
$tail->getError());

?>