Location: PHPKode > scripts > SODA > soda/SODA/SODA.inc.php
<?php

/** 
 * Main File
 * @package SODA
 * @ignore
*/

ini_set('display_errors',1);
error_reporting(E_ALL);


/** 
 * Main class: encrypt properties, load the right driver, import or export the encrypted object
 * @package SODA
 * @subpackage SODA
 * @author Salvan Gregory <hide@address.com>
 * @version 1.1
 * @copyright Copyright (c) 2008, Salvan Gregory europeaweb.com
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 * @property array $protected array of protected properties
 * @property-read array $read_only array of read only properties
 * @property-write array $write_only array of write only properties
*/
class SODA
{
/**
 * single instance of the driver class (singleton pattern)
 #
 * @access protected
 #
 * @var object 
 #
 * @static $instance
 #
*/
  protected static $instance;
/**
 * read only properties
 #
 * @access protected
 #
 * @var array 
 #
*/
  protected $read_only=array('_persistant' => '','_driver'=>'','_dbtype'=>'','_connected'=>false,'_select_db'=>false,'_requests'=>array(),'_errors'=>array());
/**
 * write only properties
 #
 * @access protected
 #
 * @var array 
 #
*/
  protected $write_only=array('_persistant' => '','_user'=>'','_pwd'=>'','_server'=>'','_dbname'=>'','_requests'=>array());
/**
 * protected properties
 #
 * @access protected
 #
 * @var array  
 #
*/
  protected $protected=array('_connection' =>'','_lock'=>false);

/**
 * private constructor prevents direct creation of object.
 #
 * 
 * @return true
*/
  private function __construct($dbtype='mysql',$nom='',$pw='',$dbname='',$srv='',$opt=array('_persistant'=>false)) 
    { 
      $classname = 'driver_' . $dbtype;
      //resolves the real dir of the main file
      $rp=realpath($_SERVER['SCRIPT_FILENAME']);
      $txt=file_get_contents($rp);
      if (preg_match("@(?<=[\"'])[^\"']*base\.inc\.php(?=[\"'])@",$txt,$ret))$dirname=dirname($ret[0]);
      else $dirname='.';
      ini_set('include_path',ini_get('include_path').":".realpath($dirname));
      $this->_basedir=$dirname.'/';
      if (file_exists($dirname.'/drivers/' . $classname . '.php') && @include_once $dirname.'/drivers/' . $classname . '.php')
        {
          self::$instance = new $classname($nom,$pw,$dbname,$srv,$opt);
          self::$instance->protected['_basedir']=$dirname.'/';
          self::$instance->protected['_driver_file']=$dirname.'/drivers/' . $classname . '.php';
          return true;
        }
      else
        {
          $drv = $this->find_drivers($dirname);
          if ($drv==false) return false;
          foreach ($drv as $classname=>$file)
            {       
              ini_set('include_path',ini_get('include_path').":".dirname($file));
              if (include_once ($file)) {
                $c= new $classname($nom,$pw,$dbname,$srv,$opt);
                if (@$c->connect())
                  {
                    $c->close();
                    self::$instance = $c;
                    self::$instance->protected['_basedir']=$this->_basedir;
                    self::$instance->protected['_driver_file']=$file;
                    return true;
                  }
              }
            }  
        }
      return false;
    }
  final private function scandir($dir)
    {
      $r=array();
      $dh = opendir($dir);
      while (($file = readdir($dh)) !== false) {
        if ($file!='.' && $file !='..') {
          if (is_dir($dir.'/'.$file)) $r=array_merge($r,$this->scandir($dir.'/'.$file));
          elseif (substr($file,0,7)=='driver_') {
            $nom=substr($file,0,strlen($file)-4);
            $r[$nom]=$dir.'/'.$file;
          }
        }
      }
      return $r;
    }
  final private function find_drivers($dir)
    {
      $dir=$dir.'/drivers';
      $r=false;
      if (is_dir($dir)) 
        {
          if ($dh = opendir($dir)) 
            {
              while (($file = readdir($dh)) !== false) 
                {
                  $d=substr($file,0,7);
                  $nom=substr($file,0,strlen($file)-4);
                  if ($d== 'driver_') $r[$nom]=$dir.'/'.$file;                 
                }
              closedir($dh);
              return $r;
            } else {
              if ($this->_basedir!='./') {
                $this->_basedir='./';
                return $this->find_drivers();
              } else return false;
            }
            
        } else {
          return $this->scandir(realpath('.'));
        }
    }
  protected function init_this() 
    {
      $this->read_only=new Array_Object($this->read_only);
      $this->write_only=new Array_Object($this->write_only);
      $this->protected=new Array_Object($this->protected);
      $this->_requests=new Array_Object(); 
      $this->_errors=new Array_Object(); 
    }
  protected function change_driver($name) 
    {
      $nom=$this->_user;
      $pw=$this->_pwd;
      $dbname=$this->_dbname;
      $srv=$this->_server;
      foreach ($this->read_only as $key=>$value) {
        if (array_key_exists($key,$this->write_only)){
          $opt[$key]=$this->$key;
        }
      }
      self::$instance=false;
      self::create($name,$nom,$pw,$dbname,$srv,$opt);
      foreach($GLOBALS as $key=>$value) {
        if ($value===$this) {
          $nm=$key;
        }
      }
      global $$nm;
      $$nm=self::$instance;
    }
/*-----------------------------------------------------------------------------
 * Method that encrypt properties: 
 * don't forget to modify it before production use for more security
--------------------------------------------------------------------------------*/
  protected function scrypt($sel,$value)
    {
      if (is_scalar($value))
        {
        /*---------------------- modify from here
        ------------------------------------------*/                  
          $pass1="passphrase1";
          $pass2="passphrase2";
          $pass3="passphrase3"; 
        //SSL encryption
        //if the protected variable $this->_certificate is not defined we create a private key and an auto trusted certificate.
        if (!array_key_exists('_certificate',$this->protected))
          {
          $this->protected['_vecteur'] = base64_encode(mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_NOFB), MCRYPT_RAND));
            $dn = array(
              "countryName" => "FR", 
              "stateOrProvinceName" => md5(mt_rand()),
              "localityName" => md5(mt_rand()),
              "organizationName" => md5(mt_rand()),
              "organizationalUnitName" => "SODA_dev",
              "commonName" => md5(mt_rand()),
              "emailAddress" => md5(mt_rand())
             );
            // create a private key
            $privkey = openssl_pkey_new();
            //create the Certificate Signing Request
            $csr = openssl_csr_new($dn, $privkey);
            //trust the request to enable the certificate
	          $sscert = openssl_csr_sign($csr, null, $privkey, 365);
	          //export to string the certificate 
            openssl_x509_export($sscert, $certout);
            //free the certificate ressource
            openssl_x509_free($sscert);
            //export to string the private key
            openssl_pkey_export($privkey, $pkeyout, $pass2);
            //free the key ressource
            openssl_free_key($privkey);
            //we store the certificate and the private key in the protected variables certificate and private_key
            $this->protected['_certificate']=base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $pass3,$certout , MCRYPT_MODE_NOFB,base64_decode($this->protected['_vecteur'])));
            $this->protected['_private_key']=base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $pass1,$pkeyout , MCRYPT_MODE_NOFB,base64_decode($this->protected['_vecteur'])));
          }
        //we get a ressource of a public key
        $certout=mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $pass3, base64_decode($this->protected['_certificate']), MCRYPT_MODE_NOFB,base64_decode($this->protected['_vecteur']));
        $public_key=openssl_pkey_get_public($certout);
        //we encrypt datas with the public key
        openssl_public_encrypt($value, $crypted, $public_key);
        //free the public key ressource
        openssl_free_key($public_key);
        //we encode the saltz to be sure that datas are crypted before decypher.
        $sel=base64_encode($sel);
        //we return saltz and encrypted value as a single string.
        return $sel.base64_encode($crypted); 
        
        /*----------------------------- modify to here
        ----------------------------------------------*/
        }
       //for array, Array_object and stdClass object we decrypt recursively
      elseif (is_array($value) || (is_object($value) && (get_class($value)=='Array_Object'||get_class($value)=='stdClass')))
        {
          $r= new Array_Object($value);
          foreach ($r as $key=>$val)
            {
              $r[$key]=$this->scrypt($key,$val);
            }
          return $r;
        }
      //ressources and complexes objects aren't stored encrypted 
      else return $value;
    }
/*-----------------------------------------------------------------------------
 * Method that decrypt properties: 
 * don't forget to modify it before production use for more security
--------------------------------------------------------------------------------*/
  protected function dcrypt($sel,$value)
    {
      if (is_string($value))
        { 
        /*---------------------- modify from here
        ------------------------------------------*/              
          $pass1="passphrase1";
          $pass2="passphrase2";
        //SSL encryption
        //we get the saltz
        $sel=base64_encode($sel);
        $len=strlen($sel);
        $begin=substr($value,0,$len);
	      //$value is encrypted ?
        if ($begin==$sel)
          {
	        //we extract the value to decypher 
            $v=base64_decode(substr($value,$len,(strlen($value)-$len)));
	        //we get a ressource of the private key
	          $pkeyout=mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $pass1,base64_decode($this->protected['_private_key']) , MCRYPT_MODE_NOFB,base64_decode($this->protected['_vecteur']));
            $private_key=openssl_pkey_get_private($pkeyout,$pass2);
	        //we decypher the variable
            $res= openssl_private_decrypt($v, $dcrypted, $private_key);
	        //free the private key ressource
            openssl_free_key($private_key);
	          //we return the decrypted value
            return $dcrypted;
          }
	      //if the value isn't encrypted we return as it. 
	      else return $value;
	      
        /*----------------------------- modify to here
        ----------------------------------------------*/
	      
        }
      //for array, Array_object and stdClass object we decrypt recursively
      elseif (is_array($value) || (is_object($value) && (get_class($value)=='Array_Object'||get_class($value)=='stdClass')))
        {        
          $r=new Array_Object($value);
          foreach ($r as $key=>$val)
            {
              $r[$key]=$this->dcrypt($key,$val);
            }
          return $r;
        }
      else return $value;
    }
/*---------------------------------------------------------------
 * overloaded functions:
---------------------------------------------------------------*/  
/**
  * override properties setting
  * @category overload
*/
  public function __set($varname,$value)
    {
      if ($this->protected['_lock']===true) {
        $this->read_only['_errors'][]="Can't set variables with locked object";       
        return;
      }
      if (isset($this->_requests[$varname])) {
        $this->_requests[$varname]=$this->scrypt($varname,$value);
        return;
      }     
      $ro=array_key_exists($varname,$this->read_only);
      $wo=array_key_exists($varname,$this->write_only);
      $pr=array_key_exists($varname,$this->protected);
      // who call ?
      $internal=false;
      $bkt=debug_backtrace();
      if(count($bkt)>1 && array_key_exists('object',$bkt[1])) {
        $internal = $bkt[1]['object']===$this;
      }
    //internal call ($this->) 
      if ($internal)
        {
          //if the array key exists in read_only or write_only and not in protected
          if (($ro || $wo) && !$pr)
            {
              $val=$this->scrypt($varname,$value);
              if($ro) $this->read_only[$varname] = $val;
              if($wo) $this->write_only[$varname]= $val;
            }
          //else the variable is protected and not crypted
          else $this->protected[$varname]=$value;
        }
    // external call: for a not defined variable or defined as a read/write or write only variable
      elseif (!$pr && (!$ro || ($ro && $wo)))
        {  
          $val=$this->scrypt($varname,$value);
          $this->write_only[$varname]=$val;
          //if the variable is defined too in read only mode or if it's not defined, it's in read and write mode
          if ($ro || (!$ro && !$wo)) {
            $this->read_only[$varname]=$val;
           }
        }
      else 
        {         
          if ($varname == '_dbtype' && $value!=$this->_dbtype) {
            $this->change_driver($value);
          } 
        }
    }
/**
  * override properties getting
  * @category overload
*/
  public function __get($varname)
    {  
      if($this->protected['_lock']===true){
        $this->read_only['_errors'][]="Can't get variables with locked object";
        return;
      }
      if (isset($this->_requests[$varname])) return $this->_requests[$varname];
      $internal=false;
      $bkt=debug_backtrace();
      if(count($bkt)>1 && array_key_exists('object',$bkt[1])) {
        $internal = $bkt[1]['object']===$this;
      }
      $ro=array_key_exists($varname,$this->read_only);
      if ($ro) {
        $r=$this->dcrypt($varname,$this->read_only[$varname]);
      } 
      elseif ($internal) {
        if (array_key_exists($varname,$this->write_only)){
          $r=$this->dcrypt($varname,$this->write_only[$varname]);
        }
        elseif (array_key_exists($varname,$this->protected)){
          $r=$this->protected[$varname];
        }
      }
      return isset($r)?$r:null;
      
    }
    
  public function __isset($varname)
    {
      $bkt=debug_backtrace();
      $internal=false;
      if(count($bkt)>1 && array_key_exists('object',$bkt[1])) {
        $internal = $bkt[1]['object']===$this;
      }
      if ($internal && array_key_exists($varname,$this->protected))return true; 
      if (array_key_exists($varname,$this->write_only)||array_key_exists($varname,$this->read_only))return true;
      return false;
    }

  public function __unset($varname)
    {
    $bkt=debug_backtrace();
    $internal=false;
    if(count($bkt)>1 && array_key_exists('object',$bkt[1])) {
      $internal = $bkt[1]['object']===$this;
    }
      if ($internal) {
        if (array_key_exists($varname,$this->read_only))unset($this->read_only[$varname]);
        if (array_key_exists($varname,$this->write_only))unset($this->write_only[$varname]);
        if (array_key_exists($varname,$this->protected))unset($this->protected[$varname]);
      } elseif (array_key_exists($varname,$this->write_only))unset($this->write_only[$varname]);
    }
 
/**
 * Prevents users to clone the object 
*/
  protected function __clone()
    {
    }

/**
 * override methods call to permit the use of natives functions of a driver 
 *
 * for example: $this->_connect is the same as mysql_connect if the driver is mysql.
 * <br/>This function use the read only variable $dbtype as a prefix for the called function 
*/
  public function __call($f,$a)
    {
      //for functions wich need a valid ressource
      $this->connect();
      foreach($a as $i=>$v) {
        $arg[]='$a['.$i.']';
      }
      if (isset($arg)&& is_array($arg))$arg=implode($arg,",");
      else $arg='';
      $b=var_export($a,true);
      $f=$this->_dbtype.$f;
      $code='$a='.$b.'; $res='.$f.'('.$arg.');';
      eval($code);
      return isset($res)?$res:false;     
    }
/**
 * Magic method that disconnect to the database before serialization  
 *
*/
  public function __sleep()
    {
      $this->close();
      foreach($this as $key => $value) {
        $r[]=$key;
      }      
      $k=md5(file_get_contents($this->_basedir."/base.inc.php"));
      $this->lock($k);
      return $r;
    }
/**
 * Magic method to reconnect to the database after unserialization  
 *
*/
  public function __wakeup()
    { 
      global $path;     
      $u=$this->unlock(md5(file_get_contents("$path/base.inc.php")));
      $c=$this->connect();
      if(!$c && !$u)$this->read_only['_errors'][]="Can't unlock the object: the file base.inc.php is different from the file wich had constructed the object";
      if(!$c && $u)$this->read_only['_errors'][]="Can't connect to the database because of bad user, password, server or database name";
      
    }

/*--------------- end of overloading
----------------------------------*/
/**
 * Method to lock the object 
 *
*/
  public function lock($key)
    {
      $pvk=$this->protected['_private_key'];
      $this->protected['_private_key']=mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,$pvk , MCRYPT_MODE_NOFB,base64_decode($this->protected['_vecteur']));
      $this->_lock_key=$this->scrypt('_lock_key',$key);
      $this->_lock=true;
      return $this->protected['_lock'];
    }
/**
 * Method to unlock the object 
 *
*/
  public function unlock($key)
    {
      $this->protected['_private_key']=mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key,$this->protected['_private_key'] , MCRYPT_MODE_NOFB,base64_decode($this->protected['_vecteur']));
      $k=$this->dcrypt('_lock_key',$this->protected['_lock_key']);
      if($k==$key){
        $this->protected['_lock']=false;
        unset($this->protected['_lock_key']);
      } else {
        $this->read_only['_errors'][]="Can't unlock this object: bad key given";
        $this->protected['_private_key']=mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,$this->protected['_private_key'], MCRYPT_MODE_NOFB,base64_decode($this->protected['_vecteur']));
      }
      return !$this->protected['_lock'];
    }
/**
 * Method to export the object as string 
 *
*/
  public function export()
    {
      $k=md5(file_get_contents($this->_basedir."/base.inc.php"));
      $s=serialize($this);
      $this->unlock($k);
      return base64_encode($s);
    }
/**
 * Method to export the object and load it in an external file  
 *
*/
  public function export_to_file($filename,$varname='$SODA_obj')
    {
      $inc='ini_get("include_path")';
      $dirname=dirname($filename);
      $bname= basename($filename);
      $df=$this->_driver_file;
      $l=strlen($dirname);
      if (substr($df,0,$l)==$dirname)$df=substr($df,$l,strlen($df)-$l);
      $f='/base.inc.php';
      $e= $this->export();
      $str='<?php
      //You can modify the path value but don\'t mofify it name:  
      $path=realpath("'.$dirname.'");
      ini_set("include_path",'.$inc.'.":$path");
      require_once("$path'.$f.'");
      require_once("$path'.$df.'");
      '.$varname.'= SODA::import("'.$e.'");
?>';
      return file_put_contents($filename,$str);
    }
/**
 * Static Method to import a SODA object 
 *
*/
  public static function import($obj)
    {
      self::$instance= unserialize(base64_decode($obj));
      return self::$instance;
    }
/**
 * Singleton pattern method contructor
 * In order to have a single instance of a class driver the real constructor is private and the construction is made by this static method
 * <br/>If an object is set this function don't create another one but return the existing object. 
*/
  public static function create($dbtype='mysql',$nom='',$pw='',$dbname='',$srv='localhost',$opt=array('_persistant'=>false)) 
    {
      if (!isset(self::$instance) || self::$instance==false) 
        {
          $r=new SODA($dbtype,$nom,$pw,$dbname,$srv,$opt);
          if(!$r) return false;            
        }
      return self::$instance;
    }

}//end of the class SODA

/**
 * This class extends the SPL object array in order to acces at arrays values with a string index like properties of an object. 
 *
 * <b>Example:</b> $mon_tableau=array('cle1'=>'valeur1');
 #
 * You can get the value of the index cle1 with:
 * - or $mon_tableau['cle1']
 * - or $mon_tableau->cle1
 * @package SODA
 * @subpackage SODA
 * @author Salvan Gregory <hide@address.com>
 * @version 1.1
 * @copyright Copyright (c) 2008, Salvan Gregory europeaweb.com
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
*/
class Array_Object extends ArrayObject
  {
    public function __construct($config = array())
      {
        parent::__construct($config, ArrayObject::ARRAY_AS_PROPS);
      }
/**
 * This method the next integer index
 * As this object extends arrays you can have integers indexes or strings indexes, it's useful to have the next integer index.  
 * <br/> Note: It return the biggest index + 1 example:Array_Object(2=>'valeur') return 3
*/
    public function count_num_index()
      { 
       $i=count($this);
       while (!array_key_exists($i-1,$this) && $i>0)$i--;
       return $i;
      }
//overloading:
    public function __set($varname,$value)
      {
        if (is_array($value))$value=new Array_Object($value);
        $this[$varname]=$value;
      }
    public function __get($varname)
      {
        if(array_key_exists($varname,$this))
          {
            if (is_array($this[$varname]))$this[$varname]= new Array_Object($this[$varname]);
            return $this[$varname];
          }
      }
    final public function __tostring()
      {
        return var_export($this,true);
      }
    public static function _new()
      {
        $numargs = func_num_args();
        $config=array();
        if ($numargs == 1)$config=func_get_arg(0);
        return new Array_Object($config);
      }
  }//end of the class Array_Object

/** 
 * This implements requests objects
 * @package SODA
 * @subpackage request
 * @author Salvan Gregory <hide@address.com>
 * @version 1.1
 * @copyright Copyright (c) 2008, Salvan Gregory europeaweb.com
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
*/
class request extends Array_Object
  {
    function __construct()
      {
        $prop= array( '_sql'=>'', 
                      '_data'=>false, 
                      '_type'=>'',
                      '_ltype'=>0,
                      '_result'=>false,
                      '_lengths'=>0,
                      '_fields'=>0,
                      '_rows'=>0,
                      '_vars'=>'',
                      '_parent'=>false
                    );
        $prop['_errors']=new Array_Object();
        $prop['_vars']= new Array_Object();
        parent::__construct($prop);
        $bkt=debug_backtrace();
        if (isset($bkt[1]['object'])) $this->_parent =&$bkt[1]['object'];
      }
/**
  *  Parses sql code and replaces variables by its values
  * @return string the correct sql code
 */
    public function get_sql()
      {
        $this->set_sql();
        $ret=$this->_sql;
        foreach ($this->_vars as $key=>$val)
          {
            if (is_int($key)) $ret=preg_replace("@[\?]@m",$val,$ret,1);
            else {
              $search="@\{$key\}@m";
              $ret=preg_replace($search,$val,$ret);
            }
          }
        return $ret;
      }
/**
  *  Analyse sql code to find variables and prepares values of replacement
  *
 */
    public function set_sql()
      {
        $value=$this->_sql;
        preg_match_all( "@\{(?>[a-z_$0-9A-Z]+)\}@xm", $value,$ar);
        if ($ar[0]!=array()) {
          foreach ($ar[0] as $val) {
            $c= count($val) - 2;
            $val=substr($val,1,$c);
            $val=trim($val);
            $$val='';
            if (isset($this->_vars[$val])) $$val=$this->_vars[$val];
            if (isset($this->$val)) {
              $$val=$this->$val;
              unset($this->$val);              
            } else {
              global $$val;
              if (!isset($$val))$$val='';
            }
            $this->_vars[$val]=$$val;
          }
        }
        $c=substr_count($value,'?');
        for ($i=0;$i<$c;$i++){
            $v=isset($this[$i])?$this[$i]:(isset($this->_vars[$i])?$this->_vars[$i]:'');
            unset($this[$i]);
            $this->_vars[$i]=$v;
        }
      }
/**
  *  deletes internal variables to prepare another request
  *
 */
    public function reset()
      {
        $this->_data=false;
        $this->_result=false;
        $this->_lengths=0;
        $this->_fields=0;
        $this->_rows=0;
        $this->_errors= new Array_Object();
      }
/**
  *  overloads methods to permit the call of parent methods as if they were defined for this object 
  *  NOTE: if this object is a property (called 'name') of the object $parent:
  * </br> $parent->name->exec() call $parent->exec('name');
 */
    public function __call($f,$a)
      {       
        if ($this->_parent !=false && isset($this->_parent->_requests))
          {
            //first we find the name of the parent property wich correspond to $this
            foreach($this->_parent->_requests as $name=>$prop) {
              if ($prop=== $this) $myname = $name;
            }
            //then we call the parent method by passing the name of $this as a parameter.
            if (isset($myname)){
              if ($f=='exec'|| $f=='clean'){
                $args=array_merge(array($myname),$a);
                return call_user_func_array(array($this->_parent, $f),$args);
              }
            }
          }
        return;
      }
  }//end of the class request 



















?>
Return current item: SODA