2019-05-30 07:32:17 +03:00
< ? php
/**
*
* @ package Kleeja
* @ copyright ( c ) 2007 Kleeja . com
* @ license ./ docs / license . txt
*
*/
//no for directly open
if ( ! defined ( 'IN_COMMON' ))
{
exit ();
}
if ( ! defined ( 'SQL_LAYER' )) :
define ( 'SQL_LAYER' , 'sqlite' );
class KleejaDatabase
{
/** @var SQLITE3 */
private $connect_id = null ;
/** @var SQLite3Result */
private $result = null ;
public $dbprefix = '' ;
private $dbname = '' ;
public $query_num = 0 ;
private $in_transaction = 0 ;
public $debugr = false ;
private $show_errors = true ;
/**
* connect
*
* @ param string $location path of sqlite database
* @ param string $db_username not needed
* @ param string $db_password not needed
* @ param string $db_name not needed
* @ param string $dbprefix tables prefix
*/
public function __construct ( $location , $db_username , $db_password , $db_name , $dbprefix )
{
2019-05-30 19:59:16 +03:00
try
{
$this -> connect_id = new SQLite3 ( PATH . $db_name , SQLITE3_OPEN_READWRITE );
}
catch ( Exception $e )
{
//...
}
2019-05-30 07:32:17 +03:00
$this -> dbprefix = $dbprefix ;
$this -> dbname = $db_name ;
//no error
if ( defined ( 'SQL_NO_ERRORS' ))
{
$this -> show_errors = false ;
}
if ( ! $this -> connect_id )
{
//loggin -> no database -> close connection
$this -> close ();
$this -> error_msg ( 'We can not connect to the sqlite database, check location or existence of the SQLite dirver ...' );
return false ;
}
//connecting
kleeja_log ( '[Connected] : ' . kleeja_get_page ());
return $this -> connect_id ;
}
public function __destruct ()
{
$this -> close ();
}
public function is_connected ()
{
return ! ( is_null ( $this -> connect_id ) || empty ( $this -> connect_id ));
}
// close the connection
public function close ()
{
if ( ! $this -> is_connected ())
{
return true ;
}
// Commit any remaining transactions
if ( $this -> in_transaction )
{
$this -> query ( 'COMMIT;' );
}
//loggin -> close connection
kleeja_log ( '[Closing connection] : ' . kleeja_get_page ());
if ( ! is_resource ( $this -> connect_id ))
{
return true ;
}
return @ mysqli_close ( $this -> connect_id );
}
// encoding functions
public function set_utf8 ()
{
//$this->set_names('utf8');
}
public function set_names ( $charset )
{
}
public function client_encoding ()
{
}
public function version ()
{
return SQLite3 :: version ();
}
/**
* execute a query
*
* @ param string $query
* @ param boolean $transaction
* @ return bool
*/
public function query ( $query , $transaction = false )
{
//no connection
if ( ! $this -> is_connected ())
{
return false ;
}
//
// Remove any pre-existing queries
//
unset ( $this -> result );
2019-05-30 19:59:16 +03:00
if ( strpos ( $query , 'CREATE TABLE' ) !== false || strpos ( $query , 'ALTER DATABASE' ) !== false )
2019-05-30 07:32:17 +03:00
{
$sqlite_types = [
2019-05-30 19:59:16 +03:00
'/AUTO_INCREMENT/i' => '' ,
'/VARCHAR\s?(\\([0-9]+\\))?/i' => 'TEXT' ,
'/COLLATE\s+([a-z0-9_]+)/i' => '' ,
'/(TINY|SMALL|MEDIUM|BIG)?INT\s?(\([0-9]+\))?\s?(UNSIGNED)?/i' => 'INTEGER ' ,
'/(TINY|MEDIUM|LONG)?TEXT/i' => 'TEXT' ,
'/KEY\s`?([a-z0-9_]+)`?\s\(`?([a-z0-9_]+)`?(\([0-9]+\))?\)\s?,?/i' => '' ,
2019-05-30 07:32:17 +03:00
'/\)(\s{0,4}ENGINE=([a-z0-9_]+))?(\s{0,4}DEFAULT)?(\s{0,4}CHARSET=([a-z0-9_]+))?(\s{0,4}COLLATE=([a-z0-9_]+))?(\s{0,4}AUTOINCREMENT)?(\s{0,4}=\s?1)?(\s{0,4};)?/i' => ')' ,
2019-05-30 19:59:16 +03:00
'/,\s+\)/' => ')' ,
'/INTEGER\s{0,4}NOT\s{0,4}NULL/i' => 'INTEGER' ,
2019-05-30 07:32:17 +03:00
];
//todo extract keys and add as CREATE INDEX index_name ON table (column);
2019-05-30 19:59:16 +03:00
foreach ( $sqlite_types as $old_type => $new_type )
2019-05-30 07:32:17 +03:00
{
$query = preg_replace ( $old_type , $new_type , $query );
}
}
if ( ! empty ( $query ))
{
//debug
$srartum_sql = get_microtime ();
if ( $transaction && ! $this -> in_transaction )
{
$this -> query ( 'BEGIN;' );
$this -> in_transaction = true ;
}
$this -> result = @ $this -> connect_id -> query ( $query );
//debug .. //////////////
$this -> debugr [ $this -> query_num + 1 ] = [ $query , sprintf ( '%.5f' , get_microtime () - $srartum_sql )];
////////////////
if ( ! $this -> result )
{
$this -> error_msg ( 'Error In query' );
}
else
{
//let's debug it
kleeja_log ( '[Query] : --> ' . $query );
}
}
else
{
if ( $this -> in_transaction )
{
$this -> result = $this -> connect_id -> query ( 'COMMIT;' );
}
}
//is there any result
if ( $this -> result )
{
if ( $this -> in_transaction )
{
$this -> in_transaction = false ;
if ( ! $this -> connect_id -> query ( 'COMMIT;' ))
{
$this -> connect_id -> query ( 'ROLLBACK;' );
return false ;
}
}
$this -> query_num ++ ;
return $this -> result ;
}
else
{
if ( $this -> in_transaction )
{
$this -> connect_id -> query ( 'ROLLBACK;' );
$this -> in_transaction = false ;
}
return false ;
}
}
/**
* build structured query [ 'SELECT' => ... , 'FROM' => ... , ... ]
*
* @ param array $query
* @ return string
*/
public function build ( $query )
{
$sql = '' ;
if ( isset ( $query [ 'SELECT' ]) && isset ( $query [ 'FROM' ]))
{
$sql = 'SELECT ' . $query [ 'SELECT' ] . ' FROM ' . $query [ 'FROM' ];
if ( isset ( $query [ 'JOINS' ]))
{
foreach ( $query [ 'JOINS' ] as $cur_join )
{
$sql .= ' ' . key ( $cur_join ) . ' ' . current ( $cur_join ) . ' ON ' . $cur_join [ 'ON' ];
}
}
if ( ! empty ( $query [ 'WHERE' ]))
{
$sql .= ' WHERE ' . $query [ 'WHERE' ];
}
if ( ! empty ( $query [ 'GROUP BY' ]))
{
$sql .= ' GROUP BY ' . $query [ 'GROUP BY' ];
}
if ( ! empty ( $query [ 'HAVING' ]))
{
$sql .= ' HAVING ' . $query [ 'HAVING' ];
}
if ( ! empty ( $query [ 'ORDER BY' ]))
{
$sql .= ' ORDER BY ' . $query [ 'ORDER BY' ];
}
if ( ! empty ( $query [ 'LIMIT' ]))
{
$sql .= ' LIMIT ' . $query [ 'LIMIT' ];
}
}
elseif ( isset ( $query [ 'INSERT' ]))
{
$sql = 'INSERT INTO ' . $query [ 'INTO' ];
if ( ! empty ( $query [ 'INSERT' ]))
{
$sql .= ' (' . $query [ 'INSERT' ] . ')' ;
}
$sql .= ' VALUES(' . $query [ 'VALUES' ] . ')' ;
}
elseif ( isset ( $query [ 'UPDATE' ]))
{
$sql = 'UPDATE ' . $query [ 'UPDATE' ] . ' SET ' . $query [ 'SET' ];
if ( ! empty ( $query [ 'WHERE' ]))
{
$sql .= ' WHERE ' . $query [ 'WHERE' ];
}
}
elseif ( isset ( $query [ 'DELETE' ]))
{
$sql = 'DELETE FROM ' . $query [ 'DELETE' ];
if ( ! empty ( $query [ 'WHERE' ]))
{
$sql .= ' WHERE ' . $query [ 'WHERE' ];
}
}
elseif ( isset ( $query [ 'REPLACE' ]))
{
$sql = 'REPLACE INTO ' . $query [ 'INTO' ];
if ( ! empty ( $query [ 'REPLACE' ]))
{
$sql .= ' (' . $query [ 'REPLACE' ] . ')' ;
}
$sql .= ' VALUES(' . $query [ 'VALUES' ] . ')' ;
}
return $this -> query ( $sql );
}
/**
* free the memmory from the last results
*
* @ param SQLite3Result $query_id optional
* @ return bool
*/
public function freeresult ( $query_id = 0 )
{
if ( ! $query_id )
{
$query_id = $this -> result ;
}
if ( $query_id )
{
$query_id -> finalize ();
return true ;
}
else
{
return false ;
}
}
/**
* fetch results ( alias of fetch_array )
*
* @ param SQLite3Result $query_id
* @ return array
*/
public function fetch ( $query_id = 0 )
{
return $this -> fetch_array ( $query_id );
}
/**
* fetch results
*
* @ param SQLite3Result $query_id
* @ return array
*/
public function fetch_array ( $query_id = 0 )
{
if ( ! $query_id )
{
$query_id = $this -> result ;
}
if ( $query_id && $query_id -> numColumns () > 0 )
{
return $query_id -> fetchArray ( SQLITE3_ASSOC );
}
return false ;
}
/**
* return number of rows of result ( not efficient )
*
* @ param SQLite3Result $query_id
* @ return int
*/
public function num_rows ( $query_id = 0 )
{
if ( ! $query_id )
{
$query_id = $this -> result ;
}
2019-05-30 19:55:49 +03:00
if ( $query_id && $results = $query_id -> numColumns ())
2019-05-30 07:32:17 +03:00
{
return $results ;
}
return false ;
}
/**
* return the id of latest inserted record
*
* @ return int
*/
public function insert_id ()
{
return $this -> is_connected () ? $this -> connect_id -> lastInsertRowID () : false ;
}
/**
* extra escape
*
* @ param string $msg
* @ return string
*/
public function escape ( $msg )
{
$msg = htmlspecialchars ( $msg , ENT_QUOTES );
$msg = $this -> real_escape ( $msg );
return $msg ;
}
/**
* escape
* @ param string $msg
* @ return int | string
*/
public function real_escape ( $msg )
{
return SQLite3 :: escapeString ( $msg );
}
/**
* number of affected rows by latest action
*
* @ return int
*/
public function affected ()
{
return $this -> is_connected () ? $this -> connect_id -> changes () : false ;
}
/**
* information
*
* @ return string
*/
public function server_info ()
{
return 'SQLite3 ' . $this -> version ();
}
/**
* present error messages
*
* @ param string $msg
* @ return void
*/
private function error_msg ( $msg )
{
if ( ! $this -> show_errors )
{
kleeja_log ( 'SQLite3: ' . $msg );
return false ;
}
2019-06-06 02:58:04 +03:00
list ( $error_no , $error_msg ) = $this -> get_error ();
2019-05-30 07:32:17 +03:00
$error_sql = @ current ( $this -> debugr [ $this -> query_num + 1 ]);
//some ppl want hide their table names
if ( ! defined ( 'DEV_STAGE' ))
{
$error_sql = preg_replace_callback ( " # \ s { 1,3}`* { $this -> dbprefix } ([a-z0-9]+)`* \ s { 1,3}# " , function ( $m ) {
return ' <span style="color:blue">' . substr ( $m [ 1 ], 0 , 1 ) . '</span> ' ;
}, $error_sql );
$error_msg = preg_replace_callback ( " # { $this -> dbname } . { $this -> dbprefix } ([a-z0-9]+)# " , function ( $m ) {
return ' <span style="color:blue">' . substr ( $m [ 1 ], 0 , 1 ) . '</span> ' ;
}, $error_msg );
$error_sql = preg_replace_callback ( " # \ s { 1,3}(from|update|into) \ s { 1,3}([a-z0-9]+) \ s { 1,3}#i " , function ( $m ) {
return $m [ 1 ] . ' <span style="color:blue">' . substr ( $m [ 2 ], 0 , 1 ) . '</span> ' ;
}, $error_sql );
$error_msg = preg_replace_callback ( " # \ s { 1,3}(from|update|into) \ s { 1,3}([a-z0-9]+) \ s { 1,3}#i " , function ( $m ) {
return $m [ 1 ] . ' <span style="color:blue">' . substr ( $m [ 2 ], 0 , 1 ) . '</span> ' ;
}, $error_msg );
$error_msg = preg_replace_callback ( " # \ s'([^']+)'@'([^']+)'#i " , function ( $m ) {
return ' <span style="color:blue">hidden</span>@' . $m [ 2 ] . ' ' ;
}, $error_msg );
$error_sql = preg_replace ( " #password \ s*= \ s*'[^']+'#i " , " password='<span style= \" color:blue \" >hidden</span>' " , $error_sql );
}
//is this error related to updating?
$updating_related = false ;
if ( strpos ( $error_msg , 'Unknown column' ) !== false || strpos ( $error_msg , 'no such table' ) !== false )
{
$updating_related = true ;
}
header ( 'HTTP/1.1 500 Internal Server Error' );
$error_message = '<html><head><title>MYSQL ERROR</title>' ;
$error_message .= " <style>BODY { font-family:'Tahoma',serif;font-size:12px;}.error { }</style></head><body> " ;
$error_message .= '<br />' ;
$error_message .= '<div class="error">' ;
$error_message .= " <a href='#' onclick='window.location.reload( false );'>click to Refresh this page ...</a><br /> " ;
$error_message .= '<h2>Sorry , We encountered a MySQL error: ' . ( $msg != '' ? $msg : '' ) . '</h2>' ;
if ( $error_sql != '' )
{
$error_message .= " <br />--[query]-------------------------- <br /> $error_sql <br />---------------------------------<br /><br /> " ;
}
$error_message .= " [ $error_no : $error_msg ] <br /> " ;
if ( $updating_related )
{
global $config ;
$error_message .= '<br /><strong>Your Kleeja database might be old, try to update it now from: ' . rtrim ( $config [ 'siteurl' ], '/' ) . '/install</strong>' ;
$error_message .= " <br /><br><strong>If this error happened after installing a plugin, add <span style= \" background-color:#ccc; padding:2px \" >define('STOP_PLUGINS', true);</span> to end of config.php file.</strong> " ;
}
$error_message .= " <br /><br /><strong>Script: Kleeja <br /><a href='http://www.kleeja.com'>Kleeja Website</a></strong> " ;
$error_message .= '</b></div>' ;
$error_message .= '</body></html>' ;
print $error_message ;
//loggin -> error
kleeja_log ( '[SQL ERROR] : "' . $error_no . ' : ' . $error_msg . '" -->' );
@ $this -> close ();
exit ();
}
/**
* return last error as [ code , message ]
*
* @ return array
*/
public function get_error ()
{
if ( $this -> connect_id )
{
return [ $this -> connect_id -> lastErrorCode (), $this -> connect_id -> lastErrorMsg ()];
}
else
{
return [ 0 , 'uknown-error-not-connected' ];
}
}
}
endif ;