PHP Classes
Icontem

File: Qtxtdb.class.php


  Search   All class groups All class groups   Latest entries Latest entries   Top 10 charts Top 10 charts   Newsletter Newsletter   Blog Blog   Forums Forums   Help FAQ Help FAQ  
  Login   Register  
Recommend this page to a friend! ReTweet ReTweet Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of mcbetter  >  QTxtDB  >  Qtxtdb.class.php  
File: Qtxtdb.class.php
Role: Class source
Content type: text/plain
Description: Qtxtdb class file
Class: QTxtDB
Manage a database stored in text files
 

Contents

Class file image Download
<?php
/**
 *
	Author&#65306;Colt Ma China
	URL&#65306;http://php.qseek.net 
	Copyright&#65306;Colt Ma China
	Join Us&#65306;Just join us and enjoy the php world. 
	Contact&#65306;qseek#163.com change # to @ 
	Version&#65306;v1.1 build 2008-02-15  *
 */

class Qtxtdb {
	// public
	var $database = '.'; // the database file directory
	var $table; // current table file name
		// $fields: key=>value mapping field name => field length
		// example: $fields = array('f1' => 5,'f2' => 15);
	var $fields = array(); // the fields of the tables
	var $count; // count of the tables
	var $content; // full content of the table file, used for searching

	/**
	 *
	 * format of th records that will be output. 
	 * default: array with number key;
	 * field: field name as keys;
	 * etc.
	 */
	var $resultFormat = 'field'; 
	var $version = 'v1.1 build 2008-02-15';
	
	// private
	var $fp;
	var $recordLength;
	var $padStr = ' ';
	var $delimiter = ',';
	var $enclosure = '"';
	var $_error = array();
	
	// public
	function Qtxtdb($database='') {
		if (!empty($database)) {
			$this->connect($database);
		}
	}

	function connect($database='') {
		if (!empty($database) and is_dir($database)) {
			$this->database = rtrim($database,'/');
			return true;
		}
		else {
			$this->_error('Fail to connect to the database.'." @ \nFILE: ".__FILE__." , \nLINE:".__LINE__." , \nFUNCTION:".__FUNCTION__." .",'db');
			return false;
		}
	}

	function close($table='') {
		if (empty($table) and isset($this->fp[$this->table])) {
			fclose($this->fp[$this->table]);
			unset($this->fp[$this->table]);
			$this->table = '';
		}
		elseif (isset($this->fp[$table])) {
			fclose($this->fp[$table]);
			unset($this->fp[$table]);
		}
	}

	function closeAll() {
		foreach ($this->fp as $k => $v) {
			fclose($v);
			unset($this->fp[$k]);
		}
		$this->table = '';
	}
	
	function selectTable($table='') {
		if (!empty($table)) {
			$this->table = $table;
		}
		if (empty($this->table)) {
			$this->_error('Table filename is empty.'." @ \nFILE: ".__FILE__." , \nLINE:".__LINE__." , \nFUNCTION:".__FUNCTION__." .",'table');
			return false;
		}
		if  (!isset($this->fp[$this->table])) {
			if ($this->fp[$this->table] = fopen("{$this->database}/{$this->table}",'r+')) {
				$this->_getHeader();
			}
		}
		return true;
	}

	function switchTable($table='') {
		if (isset($this->fp[$table])) {
			$this->table = $table;
		}
		else {
			$this->selectTable($table);
		}
	}

	function createTable($table='',$fields=array()) {
		$tmp = array();
		if (!empty($table) and !empty($fields)) {
			if ($this->fp[$table] = fopen("{$this->database}/$table",'w')) {
				$this->table = $table;
				foreach ($fields as $k => $v) {
					$tmp[$k] = $v > strlen($k) ? $v : strlen($k);
				}
				$this->fields[$table] = $tmp;
				$this->_write(array_keys($tmp));
				$this->close($table);
				return true;
			}
			else {
				$this->_error('Fail to open the table file.'." @ \nFILE: ".__FILE__." , \nLINE:".__LINE__." , \nFUNCTION:".__FUNCTION__." .",'table');
				return false;
			}
		}
		else {
			$this->_error('Unleagle table option.'." @ \nFILE: ".__FILE__." , \nLINE:".__LINE__." , \nFUNCTION:".__FUNCTION__." .",'table');
			return false;
		}
	}

	// the classic CRUD
	function add($record=array()) {
		fseek($this->fp[$this->table],0,SEEK_END);
		$this->_write($record);
		$this->count[$this->table]++;
		return $this->count[$this->table];
	}

	function find($id=0) {
		if (empty($id) or ($id<1) or ($id > $this->count[$this->table]))
			return false;
		rewind($this->fp[$this->table]);
		fseek($this->fp[$this->table],$id*$this->recordLength[$this->table]);
		$res = $this->_read();
		if (isset($res[0]) and !empty($res[0]) and !ereg('^ +$',$res[0])) {
			$res = $this->_unFormatRecord($res);
			$res = $this->formatResult($res);
			return $res;
		}
		else
			return false;
	}

	function findAll($ids='') {
		$res = array();
		if (!is_array($ids)) {
			if (empty($ids) or $ids== '*') {
				$ids = range(1,$this->count[$this->table]);
			}
			elseif (ereg(',',$ids)) {
				$tmp = explode(',',$ids);
				$ids = range($tmp[0],$tmp[1]);
			}
			else 
				return $res;
		}
		foreach ($ids as $id) {
			if ($id > $this->count[$this->table]) {
				continue;
			}
			$tmp = $this->find($id);
			if ($tmp)
				$res[] = $tmp;
		}
		return $res;
	}

	function update($id='',$record=array()) {
		if (!(empty($id) or ($id<1) or ($id > $this->count[$this->table]))) {
			fseek($this->fp[$this->table],$id*$this->recordLength[$this->table]);
			$this->_write($record);
		}
	}

	function delete($id='') {
		if (!(empty($id) or ($id<1) or ($id > $this->count[$this->table]))) {
			$record = array_pad(array(),count($this->fields[$this->table]),'');
			fseek($this->fp[$this->table],$id*$this->recordLength[$this->table]);
			$this->_write($record);
		}
	}

	/** seraching $str and return the all results.
	 * if turn on the $ergex, then search by regular express directly.
	 */

	function search($str='',$regex=false) {
		if (empty($str))
			return false;
		if ($regex) {
			$pattern = $str;
		}
		else {
			$str = preg_quote($str,'/');
			$pattern = "{$this->enclosure}.*{$str}.*{$this->enclosure}\n";
		}
		if (!$this->content[$this->table])
			$this->_readTable();
		$res = '';
		preg_match_all("/$pattern/i",$this->content[$this->table],$res);
		$res = $res[0];
		if (count($res)>0) {
			foreach($res as $k => $v) {
				$v = str_getcsv($v,$this->delimiter,$this->enclosure);
				$res[$k] = $this->_unFormatRecord($v[0]);
				$res[$k] = $this->formatResult($res[$k]);
			}
		}
		return $res;
	}

	// searching based on field $name
	function searchByField($name='',$str='',$exactly=false) {
		if (empty($name) or empty($str))
			return false;
		$fields = $this->getFields();
		$regex = array();
		foreach($fields as $v) {
			if ($v != $name)
				$regex[] = "{$this->enclosure}[^{$this->enclosure}]+{$this->enclosure}";
			else {
				if ($exactly) 
				$regex[] = "{$this->enclosure}{$str}{$this->padStr}*{$this->enclosure}";
				else
				$regex[] = "{$this->enclosure}[^{$this->enclosure}]*{$str}[^{$this->enclosure}]*{$this->enclosure}";
			}
		}
		$str = implode($this->delimiter,$regex);
		return $this->search($str,true);
	}

	// return the id of one record witch matched $str
	function getID($str='') {
		if (empty($str))
			return false;
		$str = preg_quote($str,'/');
		if (!$this->content[$this->table])
			$this->_readTable();
		$pattern = "{$this->enclosure}([0-9]+).*{$str}.*{$this->enclosure}\n";
		$res = '';
		preg_match("/$pattern/i",$this->content[$this->table],$res);
		if (isset($res[1]) and !empty($res[1])) {
			return $res[1];
		}
		return 0;
	}

	// return the count
	function getCount($str='',$regex=false) {
		if (empty($str)) 
			return $this->count[$this->table];
		return count($this->search($str,$regex));
	}
	
	function getTable() {
		return $this->table;
	}

	function getFields() {
		return array_keys($this->fields[$this->table]);
	}

	function formatResult($record=array()) {
		if (empty($record) or !is_array($record))
			return false;
		$method = '_resultIn'.ucfirst($this->resultFormat);
		if (empty($this->resultFormat) or ($this->resultFormat == 'default') or !method_exists($this,$method)) {
			return $record;
		}
		else {
			return $this->$method($record);
		}

	}

	function setResultFormat($format='') {
		$this->resultFormat = $format;
	}

	// DEBUG
	function debug($tag='') {
		echo '<div style="width:75%;float:middle"><fieldset style="background-color:#FFC"><legend style="font-weight:bold;color:#00F">Global error info</legend>';
		echo '<pre>';
		if (!empty($tag) and array_key_exists($tag,$this->_error))
			print_r($this->_error[$tag]);
		else
			print_r($this->_error);
		echo '</pre>';
		echo "</fieldset></div>";
	}


	// convert general CSV file to Qtxtdb database file
	function csvToQtxtdb($file='',$fieldsLength=array()) {
		if (empty($file) or !file_exists($file))
			return false;
		if (empty($fieldsLength) or count($fieldsLength)<1)
			$fieldsLength = $this->_genFieldsLength($file);
		if (count($fieldsLength)<1)
			return false;
		copy($file,$file.'.bak');
		$db = new Qtxtdb('.');
		$created = false;
		$handle = fopen($file.'.bak','r');
		while ($data = fgetcsv($handle, 4096)) {
			if (!$created) {
				$data = (count($data) < count($fieldsLength))? array_pad($data,count($fieldsLength),'') : $data;
				$fields = array_combine($data,$fieldsLength);
				$db->createTable(basename($file),$fields);
				$db->selectTable();
				$created = true;
			}
			else {
				$db->add($data);
			}
		}
		fclose($handle);
		$db->close();
		return true;
	}

	// convert Qtxtdb database file to general CSV file
	function QtxtdbToCsv($file='') {
		if (empty($file) or !file_exists($file))
			return false;
		$txt = implode('',file($file));
		$txt = preg_replace('/'.$this->padStr.'*'.$this->enclosure.'/',$this->enclosure,$txt);
		copy($file,$file.'.bak');
		$fp = fopen($file,'w');
		fputs($fp,$txt);
		fclose($fp);
		return true;
	}

	function version() {
		return $this->version;
	}

	// private
	function _getHeader() {
		$tmp = fgetcsv($this->fp[$this->table],4000,$this->delimiter,$this->enclosure);
		$this->fields[$this->table] = array();
		foreach ($tmp as $v) {
			$k = rtrim($v,$this->padStr);
			$this->fields[$this->table][$k] = strlen($v);
		}
		$this->recordLength[$this->table] = array_sum($this->fields[$this->table]) + count($this->fields[$this->table])*3;
		$this->count[$this->table] = floor(filesize("{$this->database}/{$this->table}")/$this->recordLength[$this->table]) - 1;
	}

	function _formatRecord($record=array()) {
		$record = str_replace($this->enclosure, $this->enclosure.$this->enclosure, $record);
		$record = str_replace("\n", '&#59336;', $record);
		foreach ($record as $k => $v) {
			$len = current($this->fields[$this->table]);
			if (strlen($v) > $len) {
				$record[$k] = $this->_fixLen($v,$len);
			}
			if (strlen($v) < $len)
				$record[$k] = str_pad($record[$k],$len,$this->padStr);
			next($this->fields[$this->table]);
		}
		reset($this->fields[$this->table]);
		return $record;
	}

	function _unFormatRecord($record=array()) {
		foreach ($record as $k => $v) {
			$record[$k] = rtrim($v,$this->padStr);
			$record[$k] = str_replace('&#59336;', "\n", $record[$k]); // replace the 'return' to some unnormal letter 
		}
		return $record;
	}

	function _fixLen($str='',$len=0) { 
		if($len>=strlen($str) or $len <= 0)
			return $str;
		$str = substr($str,0,$len);
		$p = "[".chr(0xa1)."-".chr(0xff)."]+$";
		$res = array();
		preg_match("/$p/",$str,$res);
		if (isset($res[0]) and fmod(strlen($res[0]),2) == 1)
			$str = substr($str,0,$len-1);
		return $str;
	} 

	function _fixRecord($record=array()) {
		$c = count($this->fields[$this->table]);
		$r = count($record);
		if ($r == $c)
			return $record;
		if ($r<$c)
			$res = array_pad($record,$c,'');
		else {
			$res = array_chunk($record,$c);
			$res = $res[0];
		}
		return $res;
	}

	function _write($record=array()) {
		$record = $this->_fixRecord($record);
		$record = $this->_formatRecord($record);
	//	fputcsv($this->fp[$this->table],$record,$this->delimiter,$this->enclosure);
		$str = implode("{$this->enclosure}{$this->delimiter}{$this->enclosure}", $record);
		$str = $this->enclosure.$str.$this->enclosure."\n";
		flock($this->fp[$this->table], LOCK_EX);
		if (!fwrite($this->fp[$this->table],$str)) {
			$this->_error('fail to write the record'." @ \nFILE: ".__FILE__." , \nLINE:".__LINE__." , \nFUNCTION:".__FUNCTION__." .",'write');
		}
		flock($this->fp[$this->table], LOCK_UN);
	}

	function _read() {
		return fgetcsv($this->fp[$this->table],$this->recordLength[$this->table],$this->delimiter,$this->enclosure);
	}

	function _readTable() {
		$tmp = file("{$this->database}/{$this->table}");
		unset($tmp[0]);
		$this->content[$this->table] = implode('',$tmp);
		return $this->content[$this->table];
	}

	function _countArrayLength($array = array()) {
		$res = array();
		foreach($array as $v) {
			$res[] = strlen($v);
		}
		return $res;
	}

	function _genFieldsLength($file='') {
		if (empty($file) or !file_exists($file))
			return false;
		$handle = fopen($file,'r');
		while ($data = fgetcsv($handle, 4096)) {
			if (!isset($res))
				$res = $this->_countArrayLength($data);
			else {
				$res2 = $this->_countArrayLength($data);
				$res = $this->_maxArrayLength($res,$res2);
			}
		}
		fclose($handle);
		return (isset($res))? $res : false;
	}

	function _maxArrayLength($a1=array(),$a2=array()) {
		$n = count($a1);
		$n2 = count($a2);
		if ($n>$n2) {
			$a2 = array_pad($a2,$n,0);
		}
		if ($n<$n2) {
			$n = $n2;
			$a1 = array_pad($a1,$n,0);
		}
		for ($i=0;$i<$n;$i++) {
			$a1[$i] = ($a1[$i] > $a2[$i])? $a1[$i] : $a2[$i];
		}
		return $a1;
	}

	function _resultInField($record=array()) {
		return array_combine($this->getFields(),$record);
	}

	function _error($msg='',$tag='misc') {
		if (!empty($msg)) {
			if (empty($tag)) 
				$tag = 'misc';
			$this->_error[$tag][] = $msg;
		}
	}


}

if (!function_exists('str_getcsv')):

function str_getcsv($str, $separador = ',', $delimitador = '"') {

    $md5_separador       = md5($separador);
    $md5_separador_linha = md5(time());

    $buf = '';
    $len = strlen($str);
    $aberto = false;

    for ($i = 0; $i < $len; $i++) {
        $c = $str[$i];
        switch ($c) {
        case $separador:
            if ($aberto) {
                $buf .= $c;
            } else {
                $buf .= $md5_separador;
            }
            break;
        case $delimitador:
            if ((($i+1)<$len) and ($str[$i + 1] == $delimitador)) {
                $buf .= $delimitador;
                $i++;
            } else {
                $aberto = !$aberto;
            }
            break;
        case "\n":
            if ($aberto) {
                $buf .= $c;
            } else {
                $buf .= $md5_separador_linha;
            }
            break;
        default:
            $buf .= $c;
            break;
        }
    }

    // Quebrando em linhas
    $linhas = explode($md5_separador_linha, $buf);

    // Para cada linha, quebrar em dados
    $retorno = array();
    foreach ($linhas as $linha) {
        $retorno[] = explode($md5_separador, $linha);
    }
    return $retorno;
}

endif;

if (!function_exists('array_combine')):

function array_combine($key=array(),$val=array()) {
	if (empty($key) or empty($val)) {
		return array();
	}
	$res = array();
	foreach($key as $k) {
		$res[$k] = array_shift($val);
	}
	return $res;
}

endif;

?>

 
  Advertise on this site Advertise on this site   Site map Site map   Statistics Statistics   Site tips Site tips   Privacy policy Privacy policy   Contact Contact  

For more information send a message to :
info at phpclasses dot org.
Copyright (c) Icontem 1999-2009 PHP Classes - PHP Class Scripts
  PHP Book Reviews - Reviews of books and other products