<?php
final class datafile{
private $dbpass='3954bfd28c381df8f2a66dd6e81b664e93d309fa';
private $dbpath= '';
private $table = '';
private $file;
private $fmtime;
private $lastid;
private $ci;
private $columns;
private $cidxs;
private $rows;
const pexit = "<?php exit() ?>";
const nl = "\x0A";
public function __construct($pass=''){
if(strlen($pass)!=8 || sha1($pass)!=$this->dbpass)
exit();
$this->init();
}
public function create_table($table,array$columns,$ci=true){
if(!is_string($table) || !preg_match('#^[a-z][a-z0-9_]{0,31}$#i',$table)
|| strtolower($table)=='id' || strtolower($table)=='index')
exit('<br />DB_create: invalid table name: '.$table).'<br />';
$file = $this->dbpath.'/'.$table.'.php';
if(is_file($file)){
$this->table($table);
echo '<br />DB_create: table already exists: '.$table.'<br />';
return false;
}
if(empty($columns))
exit('<br />DB_create: no column names for: '.$table.'<br />');
foreach($columns as $col)
if(!is_string($col) || !preg_match('#^[a-z][a-z0-9_]{0,31}$#i',$col)
|| strtolower($col)=='id')
exit('<br />DB_create: invalid column name for: '.$table.'<br />');
$fp = fopen($file,'wb');
flock($fp,LOCK_EX);
array_unshift($columns,'id');
$this->table = $table;
$this->file = $this->dbpath.'/'.$table.'.php';
$this->lastid = 0;
$this->ci = (bool)$ci;
$this->columns = array_values($columns);
$this->rows = array();
$this->do_write($fp);
$this->f_end($fp);
return true;
}
public function show_tables(){
$tables = array();
$scan = glob($this->dbpath.'/*.php');
foreach($scan as $file){
$f = basename($file,'.php');
if(strtolower($f)!='index')
$tables[] = $f;
}
return $tables;
}
public function is_table($table=''){
if(!in_array($table,$this->show_tables()))
return false;
return true;
}
public function drop_table($table=''){
if(!in_array($table,$this->show_tables())){
echo '<br />DB_drop_table: no such table: '.$table.'<br />';
return false;
}
unlink($this->dbpath.'/'.$table.'.php');
return true;
}
public function table($table=''){
if(!in_array($table,$this->show_tables()))
exit('<br />DB_table: no such table: '.$table.'<br />');
$this->table = $table;
$this->file = $this->dbpath.'/'.$table.'.php';
$this->load_table();
return $this->table;
}
public function insert(){
$this->tableset('insert');
$fp = $this->f_begin_rw();
$vals = func_get_args();
if(count($this->columns)-count($vals)!=1)
exit('<br />DB_insert: columns mismatch in: '.$this->table.'<br />');
array_unshift($vals,++$this->lastid);
$this->rows[] = array_values($vals);
$this->do_write($fp);
$this->f_end($fp);
return $this->lastid;
}
public function update($col,$val,array$set){
$this->tableset('update');
$this->coltest($col,'update');
foreach($set as $key=>$v)
$this->coltest($key,'update_set');
$fp = $this->f_begin_rw();
$upd = 0;
foreach($this->rows as $key=>$row)
if(!($this->ci&&strcasecmp($row[$this->cidxs[$col]],$val)
||!$this->ci&&strcmp($row[$this->cidxs[$col]],$val))){
$rowa = array_combine($this->columns,$row);
$this->rows[$key] = array_values(array_merge($rowa,$set));
if(array_diff_assoc($this->rows[$key],$row))
++$upd;
}
if($upd)
$this->do_write($fp);
$this->f_end($fp);
return $upd;
}
public function delete($col,$val){
$this->tableset('delete');
$this->coltest($col,'delete');
$fp = $this->f_begin_rw();
$del = 0;
foreach($this->rows as $key=>$row)
if(!($this->ci&&strcasecmp($row[$this->cidxs[$col]],$val)
||!$this->ci&&strcmp($row[$this->cidxs[$col]],$val))){
unset($this->rows[$key]);
++$del;
}
if($del){
$this->rows = array_values($this->rows);
$this->do_write($fp);
}
$this->f_end($fp);
return $del;
}
public function select_one($col,$val){
$this->tableset('select_one');
$this->coltest($col,'select_one');
$this->load_table();
$one = false;
foreach($this->rows as $row)
if(!($this->ci&&strcasecmp($row[$this->cidxs[$col]],$val)
||!$this->ci&&strcmp($row[$this->cidxs[$col]],$val))){
$one = (object)array_combine($this->columns,$row);
break;
}
return $one;
}
public function select_id($col,$val){
$this->tableset('select_id');
$this->coltest($col,'select_id');
$this->load_table();
$id = false;
foreach($this->rows as $row)
if(!($this->ci&&strcasecmp($row[$this->cidxs[$col]],$val)
||!$this->ci&&strcmp($row[$this->cidxs[$col]],$val))){
$id = $row[0];
break;
}
return $id;
}
public function intable($col,$val){
$this->tableset('intable');
$this->coltest($col,'intable');
$this->load_table();
$intable = false;
foreach($this->rows as $row)
if(!($this->ci&&strcasecmp($row[$this->cidxs[$col]],$val)
||!$this->ci&&strcmp($row[$this->cidxs[$col]],$val))){
$intable = true;
break;
}
return $intable;
}
public function select($col,$val,$rev=false){
$this->tableset('select');
$this->coltest($col,'select');
$this->load_table();
$sel = array();
foreach($this->rows as $row)
if(!($this->ci&&strcasecmp($row[$this->cidxs[$col]],$val)
||!$this->ci&&strcmp($row[$this->cidxs[$col]],$val)))
$sel[] = (object)array_combine($this->columns,$row);
if($rev)
return array_reverse($sel);
return $sel;
}
public function id_list($col,$val,$rev=false){
$this->tableset('id_list');
$this->coltest($col,'id_list');
$this->load_table();
$idlist = array();
foreach($this->rows as $row)
if(!($this->ci&&strcasecmp($row[$this->cidxs[$col]],$val)
||!$this->ci&&strcmp($row[$this->cidxs[$col]],$val)))
$idlist[] = $row[0];
if($rev)
return array_reverse($idlist);
return $idlist;
}
public function select_all($rev=false){
$this->tableset('select_all');
$this->load_table();
$rows = array();
foreach($this->rows as $r)
$rows[] = (object)array_combine($this->columns,$r);
if($rev)
return array_reverse($rows);
return $rows;
}
public function orderby(array$rows,array$sort){
if(empty($rows) || empty($sort))
exit('<br />DB_orderby: empty argument<br />');
foreach($rows as $k=>$obj)
$rows[$k] = (array)$obj;
$sarr = array();
foreach($sort as $col=>$ord) {
$this->coltest($col,'orderby');
$sort[$col] = strtolower($ord)=='desc'? 3:4;
$sarr[$col] = array();
foreach($rows as $k=>$r)
$sarr[$col]['_'.$k] = strtolower($r[$col]);//ci
}
$eval = 'array_multisort(';
foreach($sort as $col=>$ord)
$eval .= '$sarr[\''.$col.'\'],'.$ord.',';
$eval = substr($eval,0,-1).');';
eval($eval);
$new = array();
foreach($sarr as $col=>$arr)
foreach($arr as $k=>$v) {
$k = substr($k,1);
if(!isset($new[$k]))
$new[$k] = $rows[$k];
$new[$k][$col] = $rows[$k][$col];
}
foreach($new as $k=>$arr)
$new[$k] = (object)$arr;
return array_values($new);
}
public function get_dbpath(){
return $this->dbpath;
}
public function get_table(){
return $this->table;
}
public function get_file(){
return $this->file;
}
public function fmtime(){
return $this->fmtime;
}
public function lastid(){
return $this->lastid;
}
public function ci(){
return $this->ci;
}
public function columns(){
return $this->columns;
}
public function countrows(){
return count($this->rows);
}
private function tableset($func){
if(!$this->table)
exit('<br />DB_'.$func.': no table set<br />');
return;
}
private function coltest($col,$func){
if(!in_array($col,$this->columns))
exit('<br />DB_'.$func.': no such column<br />');
if($func=='update_set' && $col=='id')
exit('<br />DB_'.$func.': column "id" cannot be changed<br />');
return;
}
private function load_table(){
$fp = fopen($this->file,'rb');
flock($fp,LOCK_SH);
$this->do_read($fp);
flock($fp,LOCK_UN);
fclose($fp);
return;
}
private function f_begin_rw(){
$fp = fopen($this->file,'rb+');
flock($fp,LOCK_EX);
$this->do_read($fp);
return $fp;
}
private function f_end($fp){
flock($fp,LOCK_UN);
fclose($fp);
return;
}
private function do_read($fp){
fseek($fp,15);
$fm = fread($fp,17);
if($fm == $this->fmtime)
return;
$this->fmtime = $fm;
list($lastid,$ci) = explode('|',rtrim(fgets($fp),self::nl));
$this->lastid = (int)$lastid;
$this->ci = (bool)$ci;
$this->columns = unserialize(rtrim(fgets($fp),self::nl));
$this->cidxs = array_flip($this->columns);
$this->rows = unserialize(fread($fp,filesize($this->file)-ftell($fp)));
return;
}
private function do_write($fp){
$this->fmtime = number_format(microtime(true),6,'.','');
$data = self::pexit.$this->fmtime.$this->lastid.'|'.(int)$this->ci.self::nl;
$data .= serialize($this->columns).self::nl;
$data .= serialize($this->rows);
ftruncate($fp,0);
fseek($fp,0);
fwrite($fp,$data);
clearstatcache(true,$this->file);
return;
}
private function init(){
$path = $this->dbpath;
if(!$path)
$path = dirname(__FILE__).'/data';
if(!is_dir($path))
if(!mkdir($path))
exit('<br />DB_init: No such data directory: '.$path.'<br />');
$this->dbpath = realpath($path);
if(!is_file($this->dbpath.'/.htaccess')){
file_put_contents($this->dbpath.'/.htaccess','Deny from all');
file_put_contents($this->dbpath.'/index.html','');
file_put_contents($this->dbpath.'/index.php','');
}
return;
}
}
return new datafile('admin999');
?>