PHP Classes

File: Qtxtdb.class.php

Recommend this page to a friend!
  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: 16 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; ?>