File:  [Paefchen] / php / tail.class.php
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Mon Nov 26 13:05:35 2007 UTC (16 years, 5 months ago) by as
Branches: MAIN
CVS tags: HEAD
init 1.0

<?php

/**
 * Tail
 *
 * liesst eine Datei Zeilenweise aus 
 * und wartet auf aenderungen.
 *
 * @author   Aron Schlesinger <as@paefchen.net>
 * @version  1.0
 * @license  BSDL
 * @php      5
 * @cvs      $paefchen$
 *
 * Example:
 * $tail = new Tail('/var/log/access.log', 20);
 * $tail->go();
 * if ($tail->error())
 *   die($tail->getError());
 **/

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, -1, SEEK_END);
		$p = ftell($this->fh);
		
		while ($line > 0) {
			if ($p === 0)
				break;
			fseek($this->fh, --$p, SEEK_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; }
}



?>