Location: PHPKode > scripts > filesnap > filesnap/filesnap.class.php
<?php

/**
 * Snapshot File Stream Wrapper
 *
 * This class creates a new stream type that can be used when reading/writing files.
 * The class creates snapshot versions of files upon changes, and can additionally
 * retreive the contents of said file when given an arbitrary date.
 *
 * When you call the stream wrapper using snapshot://path/to/file, it will behave as if you
 * are accessing the normal local filesystem. The only difference comes into effect when
 * you attempt to modify the file, either by writing to it with fwrite or fput, or 
 * opening the file with a mode that alters the file such as mode 'w'. An unmodified
 * copy of the file will be created with an dated extension. For example, file.txt would
 * become file.txt.20061231153000. example1.php shows this functionality.
 *
 * When reading, specify your normal file path (eg. snapshot://path/to/file). You can however
 * now additionally specify a date and time to view the file with. For example, accessing
 * snapshot://path/to/file+20061231153500 would specify that you want to view the file as it 
 * was at 15:35 on 31/Dec/2006. NOTE: You cannot write to a file using this mode. Any
 * to use a mode other than 'r' will result in an error. example2.php shows this
 *  functionality.
 *
 * @author Rick Hodger <hide@address.com>
 * @version 1.0
 * @package filesnap
 * @example example1.php
 * @example example2.php
 */

class filesnap {

	var $pos = 0;
	var $fp = 0;
	var $madediff = false;
	var $src = '';

	function stream_open($path, $mode, $options, &$opened_path) {
		$this->madediff=false;
		$path = substr($path,11);
		if (substr_count($path,'+') > 0) {
			// find a specific dated version
			if ($mode==='r') {
				list($this->src,$get)=explode('+',$path);
				foreach (glob($this->src.".*") as $x) {
					$a[]=substr($x,strlen($this->src)+1);
				}
				$current=date('YmdHis',filemtime($this->src));
				sort($a);
				if($get >= $current) {
				    // do nothing, current src file is correct
				} elseif ($get <= $a[0]) {
					$this->src = $this->src.'.'.$a[0];
				} else {
					// somewhere in between
					$i=0;
					foreach($a as $b) {
						if ($get > $b) {
							break;
						}
					}
					$this->src = $this->src.'.'.$b;
				}
			} else {
				// writing to a dated file is bad, return a failure on anything but a read attempt
				return false;
			}
		} else {
			$this->src=$path;
		}
		$opened_path=$this->src;
		if ($mode==='w' || $mode==='w+') {
			$this->dodiff();
		}
		if ($mode==='r' || !file_exists($this->src)) {
			$this->madediff=true;
		}
		if ($this->fp = fopen($this->src,$mode)) {
			$this->pos = ftell($this->fp);
			return true;
		} else {
			return false;
		}
	}

	function stream_close() {
		fclose($this->fp);
	}

	function stream_read($count) {
		return fread($this->fp,$count);
	}

	function dodiff() {	
		if ($this->madediff==false) {
			copy($this->src,$this->src.'.'.date('YmdHis'));
			$this->madediff=true;
		}
	}

	function stream_write($data) {
		$this->dodiff();
		if (fwrite($this->fp,$data) != false) {;
			$this->pos = $this->pos + strlen($data);
			return strlen($data);
		} else {
			return false;
		}
	}

	function stream_eof() {
		return feof($this->fp);
	}

	function stream_tell() {
		return $this->pos;
	}

	function stream_seek($offset, $whence) {
		if (fseek($this->fp,$offset,$whence)) {
			$this->pos = ftell($this->fp);
			return true;
		} else {
			return false;
		}
	}

	function stream_flush() {
		fflush($this->fp);
	}

	function stream_stat() {
		fstat($this->fp);
	}
}

stream_wrapper_register('snapshot','filesnap')
	or die('Failed to register snapshot protocol!');

?>
Return current item: filesnap