Advertisement
bkader

Dinabase.php - CodeIgniter Flat-File Database Library

Jul 26th, 2016
141
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 11.96 KB | None | 0 0
  1. <?php
  2. defined('BASEPATH') OR exit('No direct script access allowed');
  3. /**
  4.  * Dinabase Class
  5.  *
  6.  * @package     CodeIgniter
  7.  * @subpackage  Libraries
  8.  * @author      Kader Bouyakoub <bkader@mail.com>
  9.  * @link        http://www.bkader.com/
  10.  * @license     MIT, DBAD
  11.  *
  12.  * INFORMATIONS:
  13.  *
  14.  * This library allow you to get rid of other database engine
  15.  * as its uses flat-files with content encoded usin json_ecode
  16.  * or bson_encode (if the function exists - php mongo ext needed)
  17.  *
  18.  * Make sure to create a config file for this library and name it
  19.  * "dinabase.php" inside which you put:
  20.  *
  21.  * $config['path']      path to your data folder with trailing slash.
  22.  * $config['database']  name of the main database folder.
  23.  *
  24.  * That's it! Feel free to use it by please, DBAD.
  25.  *
  26.  * HOW TO USE:
  27.  *
  28.  * You simply need to load the library inside your controller or another
  29.  * library and pass the tablename so it works.
  30.  *
  31.  * i.e: $this->load->library('dinabase', array('tablename' => 'users'));
  32.  *
  33.  * 'users' folder will be automatically created inside your data folder
  34.  * and you can after proceed to using the library.
  35.  *
  36.  * Dinabase tables accept any values types because the result will be
  37.  * either a JSON encoded or BSON encoded if you have Mongodb extension
  38.  * enabled.
  39.  *
  40.  */
  41. class Dinabase
  42. {
  43.     protected $CI;
  44.     /**
  45.      * @var string - folder where database files will be stored
  46.      */
  47.     protected $path = null;
  48.  
  49.     /**
  50.      * @var string - database name
  51.      */
  52.     protected $database = null;
  53.  
  54.     /**
  55.      * @var string - table name
  56.      */
  57.     protected $tablename = null;
  58.  
  59.     /**
  60.      * @var string - path to data folder
  61.      */
  62.     protected $data_dir = null;
  63.  
  64.     /**
  65.      * @var string - path to table folder
  66.      */
  67.     protected $table_dir = null;
  68.  
  69.     /**
  70.      * Creates a new database instance
  71.      * @access  public
  72.      * @param   string  $data_path
  73.      * @param   string  $dbname
  74.      */
  75.     public function __construct($config = array())
  76.     {
  77.         // Prepare CI object
  78.         $this->CI =& get_instance();
  79.  
  80.         // Load library configuration file
  81.         $this->CI->load->config('dinabase');
  82.  
  83.         // Prepare path to data folder
  84.         $config['path'] = config_item('path')
  85.                         ? config_item('path')
  86.                         : APPPATH.'data'.DS;
  87.         $this->path = $config['path'];
  88.        
  89.         // Create data folder if it does not already exist.
  90.         if ( ! is_dir($this->path))
  91.         {
  92.             // Create the data folder
  93.             if ( ! mkdir($this->path, 0777, true))
  94.             {
  95.                 throw new Exception("Could not create data folder. Permission Denied!");
  96.             }
  97.  
  98.             // Write our protection index.php
  99.             else
  100.             {
  101.                 $this->_create_index($this->path);
  102.             }
  103.         }
  104.  
  105.         // Set database connection
  106.         $config['database'] = config_item('database')
  107.                             ? config_item('database')
  108.                             : 'main';
  109.         $this->database = $config['database'];
  110.  
  111.         // Make sure the database folder exists or create it
  112.         if ( ! is_dir($this->path.$this->database))
  113.         {
  114.             if ( ! mkdir($this->path.$this->database, 0755, true))
  115.             {
  116.                 throw new Exception("Could not create database. Permission Denied!");
  117.             }
  118.             else
  119.             {
  120.                 $this->_create_index($this->path.$this->database);
  121.             }
  122.         }
  123.  
  124.         // Prepare table name
  125.         isset($config['tablename']) or $config['tablename'] = null;
  126.         if ($config['tablename'] !== null)
  127.         {
  128.             $this->tablename = $config['tablename'];
  129.  
  130.             //debug($this->data_dir.$this->tablename, true);
  131.             // Create the table now
  132.             if ( ! is_dir($this->data_dir.$this->tablename))
  133.                 if ( ! @mkdir($this->data_dir.$this->tablename, 0755, true))
  134.                     throw new Exception("Could not create database table. Permission Denied!");
  135.                 else
  136.                     $this->_create_index($this->data_dir.$this->tablename);
  137.         }
  138.  
  139.         $this->data_dir = $this->path.$this->database.DS;
  140.         if ($this->tablename !== null)
  141.         {
  142.             $this->table_dir = $this->data_dir.$this->tablename.DS;
  143.         }
  144.     }
  145.  
  146.     /**
  147.      * Insert new record into table
  148.      * @access  public
  149.      * @param   array   $data       array of key=>value
  150.      * @param   string  $tablename  table name
  151.      * @return  boolean
  152.      */
  153.     public function insert(array $data, $tablename = null)
  154.     {
  155.         $tablename or $tablename = $this->tablename;
  156.         if ($tablename !== null)
  157.         {
  158.             $guid = $this->_generate_guid();
  159.             $data = array_merge(array('id' => $guid), $data);
  160.             $row_file = $this->table_dir.md5($guid).'.dat';
  161.             // return serialize($data);
  162.             if ( ! file_put_contents($row_file, bson_encode($data)))
  163.                 throw new Exception("Could not insert new record.");
  164.             return true;
  165.         }
  166.         return false;
  167.     }
  168.  
  169.     /**
  170.      * Retrieves a single row by its ID
  171.      * @access  public
  172.      * @param   string  $id     ID of the row to retrieve
  173.      * @param   string  $tablename
  174.      * @return  array
  175.      */
  176.     public function find($id, $tablename = null)
  177.     {
  178.         $tablename or $tablename = $this->tablename;
  179.         return $this->find_one('id', $id, $tablename);
  180.     }
  181.  
  182.     /**
  183.      * Retrieves multiple rows by conditions
  184.      * @access  public
  185.      * @param   mixed   $field  field name or array of WHERE
  186.      * @param   mixed
  187.      * @param   string  $tablename
  188.      * @return  array
  189.      */
  190.     public function find_one($field, $match = null, $tablename = null)
  191.     {
  192.         $tablename or $tablename = $this->tablename;
  193.         if($rows = $this->_read_rows($tablename))
  194.         {
  195.             $where = (is_array($field) and $match === null)
  196.                     ? $field : array($field => $match);
  197.             if ($indexes = $this->_search_array($rows, $where))
  198.             {
  199.                 return $rows[$indexes[0]];
  200.             }
  201.             return false;
  202.         }
  203.         return false;
  204.     }
  205.  
  206.     /**
  207.      * Retrieves multiple or all rows inside a table
  208.      * @access  public
  209.      * @param   array   $where      array of WHERE statements
  210.      * @param   string  $tablename
  211.      * @return  array
  212.      */
  213.     public function find_all($where = array(), $tablename = null)
  214.     {
  215.         $tablename or $tablename = $this->tablename;
  216.         if ($rows = $this->_read_rows($tablename))
  217.         {
  218.             $_found = false;
  219.             if ($indexes = $this->_search_array($rows, $where))
  220.             {
  221.                 foreach ($indexes as $index)
  222.                 {
  223.                     $_found[$index] = $rows[$index];
  224.                 }
  225.             }
  226.             return $_found;
  227.         }
  228.         return false;
  229.     }
  230.  
  231.     /**
  232.      * Alias of the method above for CI active records fans
  233.      * @access  public
  234.      * @param   array
  235.      * @param   string
  236.      * @return  array
  237.      */
  238.     public function get_where($where = array(), $tablename = null)
  239.     {
  240.         return $this->find_all($where, $tablename);
  241.     }
  242.  
  243.     /**
  244.      * Alias of the find_all but it takes only table name
  245.      * so it retrieves all records.
  246.      * @access  public
  247.      * @param   string  $tablename
  248.      * @return  array
  249.      */
  250.     public function all($tablename = null)
  251.     {
  252.         return $this->find_all(array(), $tablename);
  253.     }
  254.  
  255.     /**
  256.      * Updates an existing row by its ID
  257.      * @access  public
  258.      * @param   string  $id     ID of the row to update
  259.      * @param   array   $data   array of SET statements
  260.      * @param   string  $tablename
  261.      * @return  boolean
  262.      */
  263.     public function update($id, array $data, $tablename = null)
  264.     {
  265.         $tablename or $tablename = $this->tablename;
  266.         if ($row = $this->find($id))
  267.         {
  268.             foreach($data as $key => $value)
  269.             {
  270.                 $row[$key] = $value;
  271.             }
  272.             $file = $this->data_dir.$tablename.DS.md5($row['id']).'.dat';
  273.             $content = function_exists('bson_encode')
  274.                         ? bson_encode($row)
  275.                         : json_encode($row);
  276.             if (file_put_contents($file, $content))
  277.                 return true;
  278.             return false;
  279.         }
  280.         return false;
  281.     }
  282.  
  283.     /**
  284.      * Updates multiple or all rows
  285.      * @access  public
  286.      * @param   array   $data   array of SET statements
  287.      * @param   array   $where  array of WHERE statements
  288.      * @param   string  $tablename
  289.      * @return  boolean
  290.      */
  291.     public function update_all(array $data, $where = array(), $tablename = null)
  292.     {
  293.         $tablename or $tablename = $this->tablename;
  294.         if ($rows = $this->find_all($where))
  295.         {
  296.             foreach($rows as $id => $row)
  297.                 $this->update($id, $data, $tablename);
  298.             return true;
  299.         }
  300.         return false;
  301.     }
  302.  
  303.     /**
  304.      * Deletes a single existing row by its ID
  305.      * @access  public
  306.      * @param   string  $id     ID of the row to delete
  307.      * @param   string  $tablename
  308.      * @return  boolean
  309.      */
  310.     public function delete($id, $tablename = null)
  311.     {
  312.         $tablename or $tablename = $this->tablename;
  313.         return $this->delete_all(array('id' => $id), $tablename);
  314.     }
  315.  
  316.     /**
  317.      * Deletes multiple or all rows by conditions
  318.      * @access  public
  319.      * @param   array   $where  array of WHERE statements
  320.      * @param   string  $tablename
  321.      * @return  boolean
  322.      */
  323.     public function delete_all($where = array(), $tablename = null)
  324.     {
  325.         $tablename or $tablename = $this->tablename;
  326.         if ($tablename !== null and $rows = $this->find_all($where))
  327.         {
  328.             foreach($rows as $id => $row)
  329.             {
  330.                 if (isset($row['deleted']))
  331.                 {
  332.                     if ((bool) $row['deleted'] === false)
  333.                     {
  334.                         $this->update($id, array(
  335.                             'deleted' => true,
  336.                             'deleted_at' => time(),
  337.                         ));
  338.                     }
  339.                 }
  340.                 else
  341.                 {
  342.                     $this->remove($id, $tablename);
  343.                 }
  344.             }
  345.             return true;
  346.         }
  347.         return false;
  348.     }
  349.  
  350.     /**
  351.      * Completely removes a single row bypassing soft delete
  352.      * @access  public
  353.      * @param   string  $id     ID of the row to delete
  354.      * @param   string  $tablename
  355.      * @return  boolean
  356.      */
  357.     public function remove($id, $tablename = null)
  358.     {
  359.         $tablename or $tablename = $this->tablename;
  360.         return $this->remove_all(array('id' => $id));
  361.     }
  362.  
  363.     /**
  364.      * Completely remove multiple or all rows bypassing soft delete
  365.      * @access  public
  366.      * @param   array   $where  array of where statements
  367.      * @param   string  $tablename
  368.      * @return  boolean
  369.      */
  370.     public function remove_all(array $where, $tablename = null)
  371.     {
  372.         $tablename or $tablename = $this->tablename;
  373.         if ($tablename !== null and $rows = $this->find_all($where))
  374.         {
  375.             $files = array();
  376.             foreach($rows as $id => $row)
  377.             {
  378.                 $files[] = $this->table_dir.md5($row['id']).'.dat';
  379.             }
  380.  
  381.             if ( ! empty($files))
  382.             {
  383.                 foreach($files as $file)
  384.                     @unlink($file);
  385.                 return true;
  386.             }
  387.             return false;
  388.         }
  389.         return false;
  390.     }
  391.  
  392.     /**
  393.      * Searches inside an array
  394.      * @access  protected
  395.      * @param   array       $array
  396.      * @param   array       $where
  397.      */
  398.  
  399.     protected function _search_array(array $array, array $where)
  400.     {
  401.         $found = false;
  402.         foreach ($array as $aKey => $aVal)
  403.         {
  404.             $coincidences = 0;
  405.             foreach ($where as $pKey => $pVal)
  406.             {
  407.                 if (array_key_exists($pKey, $aVal) && $aVal[$pKey] == $pVal)
  408.                 {
  409.                     $coincidences++;
  410.                 }
  411.             }
  412.             if ($coincidences == count($where))
  413.             {
  414.                 $found[] = $aKey;
  415.             }
  416.         }
  417.  
  418.         return $found;
  419.     }
  420.  
  421.     /**
  422.      * Read all row inside table folder
  423.      * @access  protected
  424.      * @param   string  $tablename
  425.      * @return  array
  426.      */
  427.     protected function _read_rows($tablename = null)
  428.     {
  429.         $tablename or $tablename = $this->tablename;
  430.         if ($tablename !== null)
  431.         {
  432.             $rows = array();
  433.             foreach(glob($this->table_dir.'*.dat') as $row)
  434.             {
  435.                 $index = preg_replace('/\\.[^.\\s]{3,4}$/', '', basename($row));
  436.                 $row = file_get_contents($row);
  437.                 $decoded = function_exists('bson_decode')
  438.                             ? bson_decode($row)
  439.                             : json_decode($row);
  440.                 $rows[$decoded['id']] = $decoded;
  441.             }
  442.             return $rows;
  443.         }
  444.         return false;
  445.     }
  446.  
  447.     /**
  448.      * Create the index.php protection file
  449.      * @access  protected
  450.      * @param   string $path path where the create the file
  451.      * @return  void
  452.      */
  453.     protected function _create_index($path)
  454.     {
  455.         $o = umask(0);
  456.         file_put_contents(
  457.             $path.DS.'index.php',
  458.             '<?php'."\n".'die("Directory access is forbidden.");'."\n"
  459.         );
  460.         umask($o);
  461.     }
  462.  
  463.     /**
  464.      * Generates a fresh new GUID
  465.      * @access  protected
  466.      * @param   none
  467.      * @return  string
  468.      */
  469.     protected function _generate_guid($striped = true)
  470.     {
  471.         $guid = '%04x%04x-%04x-%04x-%04x-%04x%04x%04x';
  472.         if ($striped === true)
  473.             $guid = '%04x%04x%04x%04x%04x%04x%04x%04x';
  474.  
  475.         return vsprintf($guid, array(
  476.             mt_rand(0, 0xffff), mt_rand(0, 0xffff),
  477.             mt_rand(0, 0xffff),
  478.             mt_rand(0, 0x0fff) | 0x4000,
  479.             mt_rand(0, 0x3fff) | 0x8000,
  480.             mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff),
  481.         ));
  482.     }
  483. }
  484.  
  485. /* End of file Dinabase.php */
  486. /* Location: ./application/libraries/Dinabase.php */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement