Login   Register  
PHP Classes
elePHPant
Icontem

File: Qtxtdb.class.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of mcbetter  >  QTxtDB  >  Qtxtdb.class.php  >  Download  
File: Qtxtdb.class.php
Role: Class source
Content type: text/plain
Description: Qtxtdb class file
Class: QTxtDB
Manage a database stored in text files
Author: By
Last change: fix the method createTable
Date: 6 years ago
Size: 14,982 bytes
 

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;

?>