Location: PHPKode > projects > ATUIN > atuin/app/models/dbapi/DBApi.php
<?php

require_once 'DBTree.php';

class DBApi {

   private $dbfile;
   private $dbtree;
   private $DATA_DEF; // first entry in data_def is used as primary key
   private $ENTRY_SIZE;

   function __construct( $file) {
      $this->dbfile = $file;
      $treefile = preg_replace( '/\..*/', '.tree', $file);
      $this->dbtree = new DBTree( $treefile);
      $this->ENTRY_SIZE = 0;
      if( file_exists( $file)) {
         // read data definition
         $i = 0;
         $dd = preg_split( '/;/', $this->dbtree->getValue( 'data_def'));
         foreach( $dd as $def) {
            if( strlen( $def)>0) {
               $split = preg_split( '/:/', $def);
               $l = strpos( $split[1], '[');
               $r = strlen( $split[1])-1;
               $size = substr( $split[1], $l+1, $r-$l-1);
               $this->ENTRY_SIZE += $size;
               $this->DATA_DEF[$i] = array( $split[0] => $split[1]);
               $i++;
            }
         }
      }
      else {
         $this->DATA_DEF = array( );
      }  
   }
   
   public function __set( $name, $value) {
      switch( $name) {
         case 'dbfile':
            $this->dbfile = $value;
            break;   
         case 'dbtree':
            $this->dbtree = $value;
            break;   
         case 'DATA_DEF':
            $this->DATA_DEF = $value;
            break;
         case 'ENTRY_SIZE':
            $this->ENTRY_SIZE = $value;
            break;
      }
   }

   public function __get( $name) {
      switch( $name) {
         case 'dbfile':
            return $this->dbfile;
         case 'dbtree':
            return $this->dbtree;
         case 'DATA_DEF':
            return $this->DATA_DEF;
         case 'ENTRY_SIZE':
            return $this->ENTRY_SIZE;
      }
   }

   public function exists( ) {
      return count( $this->DATA_DEF)>0;
   }

   private function getDD( $i) {
      if( !$this->exists( ))
         return array( );
      $j = 0;
      foreach( $this->DATA_DEF as $dd) {
         if( $i==$j) {
            foreach( $dd as $name => $value) {
               $l = strpos( $value, '[');
               $r = strpos( $value, ']');
               $size = substr( $value, $l+1, $r-$l-1);
               $type = substr( $value, 0, $l);
               return array( 'name' => $name, 'type' => $type, 'size' => $size);
            }
         }
         $j++;
      }
      return array( );
   }

   public function createDB( $data_definition) {
      if( $this->exists( ))
         return;
      $dd = '';
      $this->ENTRY_SIZE = 0;
      $i = 0;
      foreach( $data_definition as $name => $value) {
         if( $i>0) {
            $dd .= ';';
         }
         $value = strtoupper( str_replace( ' ', '', $value));
         $dd .= $name . ':' . $value;
         $l = strpos( $value, '[');
         $r = strpos( $value, ']');
         $size = substr( $value, $l+1, $r-$l-1);
         $this->ENTRY_SIZE += $size;
         array_push( $this->DATA_DEF, array( $name => $value));
         $i++;
      }
      $treefile = preg_replace( '/\.db/', '.tree', $this->dbfile);
      if( file_exists( $treefile)) {
         unlink( $treefile);
      }
      if( file_exists( $this->dbfile)) {
         unlink( $this->dbfile);
      }
      // save data def in root of tree
      $this->dbtree->addKey( 'data_def', $dd);
   }

   public function getEntry( $key) {
      if( !$this->exists( )) {
         return array( );
      }
      $keyDD = $this->getDD( 0);
      if( strlen( $key)>$keyDD['size'])
         $key = substr( $key, 0, $keyDD['size']);
      $value = $this->dbtree->getValue( $key);
      $entry = array( );
      if( $value!==false) {
         $BLOCKSTART = $value * $this->ENTRY_SIZE;
         $fh = fopen( $this->dbfile, 'r') or die( $php_errormsg);
         fseek( $fh, $BLOCKSTART, SEEK_SET);
         $i = 0;
         $dd = $this->getDD( $i);
         while( !empty( $dd)) {
            $data = rtrim( fread( $fh, $dd['size']));
            $hlp = array( $dd['name'] => $data);
            $entry = array_merge( $entry, $hlp);
            $i++;
            $dd = $this->getDD( $i);
         }
         fclose( $fh);
      }
      return $entry;
   }
   
   public function updateEntry( $entry) {
      if( $this->exists( )) {
         $keyDD = $this->getDD( 0);
         if( empty( $keyDD))
            return;
         $key = $entry[$keyDD['name']];
         if( strlen( $key)>$keyDD['size'])
            $key = substr( $key, 0, $keyDD['size']);
         $value = $this->dbtree->getValue( $key);
         if( $value!==false) {
            $i = 0;
            $dd = $this->getDD( $i);
            $str = '';
            $data = '';
            while( !empty( $dd)) {
               $str = $entry[$dd['name']];
               if( strlen( $str)>$dd['size']) { // input is too long -- trim to correct size
                  $str = substr( $str, 0, $dd['size']);
               }
               else { // append ' ' until str has correct size
                  while( strlen( $str)<$dd['size']) {
                     $str .= ' '; // fill rest with blanks
                  }
               }
               $data .= $str;
               $i++;
               $dd = $this->getDD( $i);
            }
            $BLOCKSTART = $value * $this->ENTRY_SIZE;
            $filesize = filesize( $this->dbfile);
            $fh = fopen( $this->dbfile, 'r+') or die( $php_errormsg);
            fseek( $fh, $BLOCKSTART, SEEK_SET);
            fwrite( $fh, $data);
            fflush( $fh);
            fclose( $fh);
         }
      }
   }

   public function addEntry( $entry) {
      if( $this->exists( )) {
         $keyDD = $this->getDD( 0);
         if( empty( $keyDD))
            return;
         $key = $entry[$keyDD['name']];
         if( strlen( $key)>$keyDD['size'])
            $key = substr( $key, 0, $keyDD['size']);
         $value = $this->dbtree->getValue( $key);
         if( $value===false) {
            $fh = fopen( $this->dbfile, 'a') or die( $php_errormsg);
            fseek( $fh, 0, SEEK_END);
            $BLOCKSTART = ftell( $fh);
            $i = 0;
            $dd = $this->getDD( $i);
            $loc = 0;
            $str = '';
            $data = '';
            while( !empty( $dd)) {
               fseek( $fh, $loc, $BLOCKSTART);
               $str = $entry[$dd['name']];
               if( strlen( $str)>$dd['size']) { // input is too long -- trim to correct size
                  $str = substr( $str, 0, $dd['size']);
               }
               else { // append ' ' until str has correct size
                  while( strlen( $str)<$dd['size']) {
                     $str .= ' '; // fill rest with blanks
                  }
               }
               $data .= $str;
               $loc += $dd['size'];
               $i++;
               $dd = $this->getDD( $i);
            }
            fwrite( $fh, $data);
            fflush( $fh);
            fclose( $fh);
            $this->dbtree->addKey( $key, $BLOCKSTART/$this->ENTRY_SIZE);
         }
         else {
            // ignore operation
         }
      }
   }
   
   /* bearbeiten */
   public function getKeysByRow( $id) {
      if( !$this->exists( )) {
         return array( );
      }
      $i = 0;
      $dd = $this->getDD( $i);
      $row = -1;
      $row_name = '';
      $row_type = '';

      while( !empty( $dd) && $row==-1) {
         if( strcmp( $id, $dd['name'])==0) {
            $row = $i;
            $row_name = $dd['name'];
            $row_type = $dd['type'];
         }
         $i++;
         $dd = $this->getDD( $i);      
      }

      if( strlen( $row)==0 || $row==-1) {
         return array( );
      }

      $allKeys = $this->dbtree->getAllKeys( );
      $allKeysByRow = array( );
      $dd = $this->getDD( 0);
      $key_type = $dd['type'];

      if( $row==0) { // requested keys in ascending order
         foreach( $allKeys as $k) {
            if( strcmp( $k, 'data_def')!=0) {
               $allKeysByRow[$k] = $k;
            }
         }
      }
      else {
         $dd = $this->getDD( $row);
         $SIZE = $dd['size'];
         $BLOCKSTART = 0;
         $REL = 0;
         for( $i = 0; $i<$row; $i++) {
            $dd = $this->getDD( $i);
            $REL += $dd['size'];   
         }
         $fh = fopen( $this->dbfile, 'r') or die( $php_errormsg);
         foreach( $allKeys as $k) {
            if( strcmp( $k, 'data_def')!=0) {
               $value = $this->dbtree->getValue( $k);
               if( $value!==false) {
                  $BLOCKSTART = $value * $this->ENTRY_SIZE + $REL;
                  fseek( $fh, $BLOCKSTART, SEEK_SET);
                  $data = rtrim( fread( $fh, $SIZE));
                  if( isset( $allKeysByRow[$data])) {
                     if( is_array( $allKeysByRow[$data])) {
                        $allKeysByRow[$data] = array_merge( $allKeysByRow[$data], array( $k));
                     }
                     else {
                        $hlp = $allKeysByRow[$data];
                        $allKeysByRow[$data] = array( $hlp, $k);
                     }
                     switch( $key_type) {
                        case 'NUM':
                           sort( $allKeysByRow[$data], SORT_NUMERIC);
                           break;
                        case 'CHR':
                           sort( $allKeysByRow[$data], SORT_STRING);
                           break;
                     }
                  }
                  else {
                     $allKeysByRow[$data] = $k;
                  }
               }
            }
         }
         fclose( $fh);
      }
      switch( $row_type) {
         case 'NUM':
            ksort( $allKeysByRow, SORT_NUMERIC);
            break;
         case 'CHR':
            ksort( $allKeysByRow, SORT_STRING);
            break;
      }
      return $allKeysByRow;           
   }
   
   public function removeEntry( $key) {
      if( $this->exists( )) {
         $keyDD = $this->getDD( 0);
         if( strlen( $key)>$keyDD['size'])
            $key = substr( $key, 0, $keyDD['size']);
         $this->dbtree->removeKey( $key);
      }
   }

   public function printDataDef( ) {
      if( !$this->exists( )) {
         echo 'the specified db does not even exist.';
         return;
      }
      echo 'data definition of "' . $this->dbfile . '":<br />';
      $i = 0;
      $dd = $this->getDD( $i);
      while( !empty( $dd)) {
         echo ($i+1) . '. ' . $dd['name'] . ' : ' . $dd['type'] . '[' . $dd['size'] .']<br />';
         $i++;
         $dd = $this->getDD( $i);
      }
      echo '<br />';
   }
};

?>
Return current item: ATUIN