Passed
Push — dev ( d62152...d10d14 )
by Salim
03:23
created

Database::PrepareLogSQL()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 19
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 16
nc 2
nop 2
dl 0
loc 19
c 0
b 0
f 0
cc 2
rs 9.7333
1
<?php
2
3
/**
4
 *	Class Database (PDO Extension)
5
 *  ---------------------------- 
6
 *  Description : encapsulates database operations & properties with PDO
7
 *  Updated	    : 22.05.2013
8
 *  Version     : 1.0.7
9
 *	Written by  : ApPHP
10
 *	Used in     : DataGridWizard, AdminPanel, EasyInstaller
11
 *	Syntax (standard)  : $db = new Database($database_host, $database_name, $database_username, $database_password, EI_DATABASE_TYPE, $is_installation);
12
 *	Syntax (singleton) : $db = Database::GetInstance($database_host, $database_name, $database_username, $database_password, EI_DATABASE_TYPE, $is_installation);
13
 *
14
 *  PUBLIC              STATIC				 PROTECTED           PRIVATE
15
 *  -------             ----------          ----------          ---------- 
16
 *  __construct         GetInstance                             PrepareLogSQL
17
 *	__destruct          IsConnected
18
 *	Create
19
 *	AllowTransactions
20
 *	Open             
21
 *	Close
22
 *	CloseCursor
23
 *	GetVersion
24
 *	GetDbDriver
25
 *	Query
26
 *	Exec
27
 *	AffectedRows
28
 *	RowCount
29
 *	ColumnCount
30
 *	InsertID
31
 *	SetEncoding
32
 *	Error
33
 *	ErrorCode
34
 *	ErrorInfo
35
 *	FetchAssoc
36
 *	FetchArray
37
 *	ShowTables
38
 *	ShowColumns
39
 *
40
 *	CHANGE LOG
41
 *	-----------
42
 *  1.0.7
43
 *      - added CloseCursor()
44
 *      - added "persistent_connection" (default - false)
45
 *      -
46
 *      -
47
 *      -
48
 *  1.0.6
49
 *      - changed syntaxt for mssql to 'sqlsrv'
50
 *      - added $PROJECT
51
 *      - returned old syntax for 'mssql'
52
 *      - added sqlsrv in ShowTables()
53
 *      - added $this->sth = null; to Query()
54
 *  1.0.5
55
 *      - removed Query() from ShowColumns() and ShowTables()
56
 *      - added AllowTransactions()
57
 *      - added schema parameter for ShowTables/ShowColumns
58
 *      - added ` for some queries
59
 *      - fixed some syntaxt errors for mssql in ShowColumns and ShowTables
60
 *  1.0.4
61
 *      - added ShowTables()
62
 *      - PrepareLogSQL code placed in separated function
63
 *      - updated ShowTables()
64
 *      - added additional check if object exists for Query, Exec etc. methods
65
 *      - added ShowColumns()
66
 *  1.0.3
67
 *      - improved Exec() - added $check_error parameter
68
 *      - improved Query() - added fetch type
69
 *      - added oci connection case in Open() method
70
 *      - improved oci connection string
71
 *      - added connect syntaxt for 'ibm'
72
 *  1.0.2
73
 *  	- added FetchAssoc()
74
 *  	- fixed bug in RowCount
75
 *  	- fixed bug in GetInstance()
76
 *  	- added IsConnected()
77
 *  	- fixed error with $installation property
78
 *	
79
 **/
80
81
class Database
82
{
83
    // connection parameters
84
	private $host = '';
85
	private $port = '';
86
	private $ssl;
87
	private $db_driver = '';
88
    private $database = '';
89
    private $user = '';
90
    private $password = '';
91
    private $allow_transactions = false;
92
	private $force_encoding = false;
93
    private $persistent_connection = false;
94
	private static $installation = false;
95
	private $use_mysql = false;
96
97
	private $error = '';
98
	private $affectedRows = '0';
99
    // database connection handler 
100
    private $dbh = NULL;
101
	// database statament handler 
102
	private $sth = NULL;
103
	// static data members	
104
	private static $objInstance; 
105
106
	// DataGridWizard, AdminPanel, EasyInstaller
107
	private static $PROJECT = 'EasyInstaller';  
108
109
110
	//==========================================================================
111
    // Class Constructor
112
	// 		@param $database_host
113
	// 		@param $database_name
114
	// 		@param $database_username
115
	// 		@param $database_password
116
	// 		@param $db_driver
117
	// 		@param $force_encoding
118
	// 		@param $is_installation
119
	//==========================================================================
120
    function __construct($database_host='', $database_name='', $database_username='', $database_password='', $db_driver='', $force_encoding=false, $is_installation=false, $ssl=false)	
121
    {
122
		$this->host = $database_host;
123
		$this->port = '';
124
		$this->ssl=$ssl;
125
		$host_parts = explode(':', $database_host);		
126
		if(isset($host_parts[1]) && is_numeric($host_parts[1])){
127
			$this->host = $host_parts[0];	
128
			$this->port = $host_parts[1];	
129
		}
130
		
131
		if($database_host == '' && $database_name == ''){
132
			$config = new Config();	
133
			$this->host = $config->getHost();
134
			$this->user = $config->getUser();
135
			$this->password = $config->getPassword();
136
			$this->database = $config->getDatabase();
137
			$this->db_driver = $config->getDatabaseType();
138
            $this->allow_transactions = false;
139
		}else{
140
			$this->database  = $database_name;   	
141
			$this->user 	 = $database_username;
142
			$this->password  = $database_password;
143
			$this->db_driver = strtolower($db_driver);
144
			$this->allow_transactions = false;
145
		}
146
		$this->force_encoding = $force_encoding;
147
		
148
		self::$installation = ($is_installation) ? true : false;
149
	}
150
151
	//==========================================================================
152
    // Class Destructor
153
	//==========================================================================
154
    function __destruct()
155
	{
156
		// echo 'this object has been destroyed';
157
    }
158
159
    /**
160
     *	Allow transactions
161
     *	    @param $mode
162
     */
163
    public function AllowTransactions($mode = false)
164
    {
165
        $this->allow_transactions = ($mode == true) ? $mode : false;
166
    }
167
168
    /**
169
     *	Create database
170
     */
171
    public function Create()
172
    {
173
		$this->dbh = new PDO($this->db_driver.':host='.$this->host, $this->user, $this->password);
174
		$this->dbh->exec('CREATE DATABASE IF NOT EXISTS `'.$this->database.'`;');
175
		if($this->dbh->errorCode() != '00000'){
176
			$err = $this->dbh->errorInfo();
177
			$this->error = $err[2];
178
			return false; 
179
		}
180
		return true; 
181
	}
182
183
    /**
184
     *	Checks and opens connection with database
185
     */
186
    public function Open()
187
    {
188
        // Without PDO extension
189
        if($this->use_mysql && $this->db_driver == 'mysql'){
190
            // Choose the appropriate connect function 
191
            if($this->persistent_connection){
192
                $func = 'mysql_pconnect';
193
            } else {
194
                $func = 'mysql_connect';
195
            }    
196
            // Connect to the MySQL server 
197
            $this->dbh = $func($this->host, $this->user, $this->password);
198
            return true;
199
        }
200
        
201
        // With PDO extension
202
		if(version_compare(PHP_VERSION, '5.0.0', '<') || !defined('PDO::ATTR_DRIVER_NAME')){
203
			$this->error = 'You must have PHP 5 or newer installed to use PHP Data Objects (PDO) extension';
204
			return false; 
205
		}
206
207
		$port = (!empty($this->port)) ? ';port='.$this->port : '';
208
		try{
209
			switch($this->db_driver){
210
				case 'mssql':
211
                    $this->dbh = new PDO('mssql:host='.$this->host.$port.';dbname='.$this->database, $this->user, $this->password);
212
					break;
213
                case 'sqlsrv': 
214
                    $this->dbh = new PDO('sqlsrv:Server='.$this->host.$port.';Database='.$this->database, $this->user, $this->password);
215
					break;
216
				case 'sybase': 
217
					$this->dbh = new PDO('sybase:host='.$this->host.$port.';dbname='.$this->database, $this->user, $this->password);
218
					break;
219
				case 'sqlite':
220
					$this->dbh = new PDO('sqlite:my/database/path/database.db');
221
					break;
222
				case 'pgsql':
223
					$this->dbh = new PDO('pgsql:host='.$this->host.$port.';dbname='.$this->database, $this->user, $this->password);
224
					break;
225
                case 'ibm': 
226
                    $this->dbh = new PDO('ibm:'.$this->database, $this->user, $this->password);
227
                    break;
228
				case 'oci':
229
					// Look for valid parameters in product\10.2.0\server\NETWORK\ADMIN	
230
					// Example: $tns = '(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = private-22269fa)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = XE) ))';
231
					$port = (!empty($this->port)) ? $this->port : '1521';
232
					$tns = '(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = '.$this->host.')(PORT = '.$port.')) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = '.$this->database.') ))';
233
					$this->dbh = new PDO('oci:dbname='.$tns, $this->user, $this->password);
234
					break;
235
				case 'mysql':
236
				default:
237
                    if($this->ssl){
238
                        $sslOptions = array(
239
                            PDO::MYSQL_ATTR_SSL_CA => '',
240
                            PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false
241
                        );
242
                        $this->dbh = new PDO($this->db_driver.':host='.$this->host.$port.';dbname='.$this->database, $this->user, $this->password, $sslOptions);
243
                        
244
                    }else{
245
                        $this->dbh = new PDO($this->db_driver.':host='.$this->host.$port.';dbname='.$this->database, $this->user, $this->password);
246
                        
247
                    }
248
                    $this->dbh->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
249
                    
250
                    if($this->persistent_connection) $this->dbh->setAttribute(PDO::ATTR_PERSISTENT, true);
251
					break;
252
			}
253
			$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
254
			if(empty($this->dbh)){
255
				return false;
256
			}else if($this->force_encoding){
257
				$this->dbh->exec('set names utf8');
258
			}
259
		}catch(PDOException $e){  
260
			$this->error = $e->getMessage();
261
			return false; 
262
		}            
263
264
        return true;
265
    }	
266
    
267
    /**
268
     *	Close connection 
269
     */
270
    public function Close()
271
    {
272
		$this->sth = null;
273
		$this->dbh = null;
274
    }
275
276
	/**
277
	 * Close cursor
278
	 * The following call to closeCursor() may be required by some drivers
279
	 */
280
    public function CloseCursor()
281
    {
282
		return ($this->dbh) ? $this->dbh->closeCursor() : '';
283
    }
284
285
    /**
286
     *	Returns database engine version
287
     */
288
	public function GetVersion()
289
	{
290
        if($this->use_mysql && $this->db_driver == 'mysql'){
291
            $version = mysql_get_server_info();
292
        }else{
293
            $version = $this->dbh->getAttribute(PDO::ATTR_SERVER_VERSION);
294
        }
295
        // clean version number from alphabetic characters
296
		return preg_replace('/[^0-9,.]/', '', $version);
297
	}
298
299
    /**
300
     *	Get DB driver
301
     */
302
    public function GetDbDriver()
303
    {
304
		return $this->db_driver;
305
    }
306
307
    /**
308
     *	Runs query
309
     *		@param $query
310
     *		@param $fetch_mode
311
     */
312
    public function Query($query = '', $fetch_mode = PDO::FETCH_ASSOC)
313
    {
314
        if(!$this->dbh || empty($query)) return false;
315
        
316
        if($this->use_mysql && $this->db_driver == 'mysql'){
317
            $this->sth = mysql_query($query, $this->dbh);            
318
            return ($this->sth != false);            
319
        }else{
320
            try{  
321
                $this->sth = $this->dbh->query($query);
322
                if($this->sth !== FALSE){
323
                    $this->sth->setFetchMode($fetch_mode);
324
                    return $this->sth;
325
                }
326
                else return false; 
327
            }catch(PDOException $e){
328
                $this->error = $e->getMessage();
329
                $this->sth = null;
330
                if(!self::$installation){
331
                    $sql_log = $this->PrepareLogSQL($e, $query);
332
                    $this->Exec($sql_log);
333
                }
334
                return false; 
335
            }                        
336
        }    
337
    }
338
339
    /**
340
     *	Executes query
341
     *		@param $query
342
     *		@param $check_error
343
     */
344
    public function Exec($query = '', $check_error = true)
345
	{
346
        if(!$this->dbh) return false;
347
        if(empty($query)) return false;  
348
		try{
349
			$this->affectedRows = $this->dbh->exec($query);
350
			return $this->affectedRows;	
351
		}catch(PDOException $e){            
352
			if($check_error){
353
				$this->error = $e->getMessage();				
354
				if(!self::$installation){
355
					$sql_log = $this->PrepareLogSQL($e, $query);
356
					$this->Query($sql_log);
357
				}				
358
			}			
359
			return false; 
360
		}		
361
	}
362
363
    /**
364
     *	Set encoding and collation on database
365
     *		@param $encoding
366
     *		@param $collation
367
     */
368
    public function SetEncoding($encoding = 'utf8', $collation = 'utf8_unicode_ci')
369
    {		
370
		if(empty($encoding)) $encoding = 'utf8';
371
        if(empty($collation)) $collation = 'utf8_unicode_ci';    
372
        $sql_variables = array(
373
                'character_set_client'  =>$encoding,
374
                'character_set_server'  =>$encoding,
375
                'character_set_results' =>$encoding,
376
                'character_set_database'=>$encoding,
377
                'character_set_connection'=>$encoding,
378
                'collation_server'      =>$collation,
379
                'collation_database'    =>$collation,
380
                'collation_connection'  =>$collation
381
        );
382
        foreach($sql_variables as $var => $value){
383
            $sql = 'SET '.$var.'='.$value;
384
            $this->Query($sql);
385
        }        
386
    }
387
388
    /**
389
     *	Returns affected rows after exec()
390
     */
391
    public function AffectedRows()
392
    {
393
		return $this->affectedRows;
394
    }	
395
396
    /**
397
     *	Returns rows count for query()
398
     */
399
    public function RowCount()
400
    {
401
		return (isset($this->sth)) ? $this->sth->rowCount() : 0; 
402
    }		
403
404
    /**
405
     *	Returns columns count for query()
406
     */
407
    public function ColumnCount()
408
    {
409
		return $this->sth->columnCount(); 
410
    }		
411
412
    /**
413
     *	Returns last insert ID
414
     */
415
	public function InsertID()
416
    {
417
		return $this->dbh->lastInsertId();
418
    }
419
420
    /**
421
     *	Returns error 
422
     */
423
    public function Error()
424
    {
425
		return $this->error;		
426
    }
427
	
428
    /**
429
     *	Returns error code
430
     */
431
    public function ErrorCode()
432
    {
433
        return ($this->dbh) ? $this->dbh->errorCode() : false;
434
    }
435
436
    /**
437
     *	Returns error code
438
     */
439
    public function ErrorInfo()
440
    {
441
		return ($this->sth) ? $this->sth->errorInfo() : false;
442
    }
443
 
444
	/**
445
	 * Fetch assoc
446
	 */
447
    public function FetchAssoc()
448
    {
449
		return ($this->sth) ? $this->sth->fetch(PDO::FETCH_ASSOC) : false;
450
    }
451
 
452
	/**
453
	 * Fetch array
454
	 */
455
    public function FetchArray()
456
    {
457
		return ($this->sth) ? $this->sth->fetch(PDO::FETCH_BOTH) : false;
458
    }
459
	
460
	/**
461
	 * Show tables from current database
462
	 *      @param $schema
463
	 */
464
    public function ShowTables($schema = '')
465
    {
466
		switch($this->db_driver){
467
			case 'mssql';
468
            case 'sqlsrv':
469
				$sql = 'SELECT * FROM sys.all_objects WHERE type = \'U\'';
470
				break;
471
            case 'pgsql':
472
                $sql = 'SELECT tablename FROM pg_tables WHERE tableowner = current_user';
473
                break;
474
            case 'sqlite':
475
                $sql = 'SELECT * FROM sqlite_master WHERE type=\'table\'';
476
                break;
477
			case 'oci':
478
				$sql = 'SELECT * FROM system.tab';
479
				break;
480
			case 'ibm':
481
				$sql = 'SELECT TABLE_NAME FROM qsys2.systables'.(($schema != '') ? ' WHERE TABLE_SCHEMA = \''.$schema.'\'' : '');
482
				break;
483
			case 'mysql':
484
			default:
485
				$sql = 'SHOW TABLES IN `'.$this->database.'`';	
486
				break;
487
		}
488
        return $sql;
489
    }
490
	
491
	/**
492
	 * Show columns from current database
493
	 */
494
    public function ShowColumns($table, $schema = '')
495
    {
496
		switch($this->db_driver){
497
			case 'ibm':
498
                $sql = 'SELECT COLUMN_NAME FROM qsys2.syscolumns WHERE TABLE_NAME = \''.$table.'\''.(($schema != '') ? ' AND TABLE_SCHEMA = \''.$schema.'\'' : ''); 
499
				break;
500
			case 'mssql':
501
                $sql = 'select COLUMN_NAME, data_type, character_maximum_length from '.$this->database.'.information_schema.columns where table_name = \''.$table.'\'';
502
				break;
503
			case 'mysql':
504
			default:
505
				$sql = 'SHOW COLUMNS FROM `'.$table.'`';
506
				break;
507
		}
508
        return $sql;
509
    }
510
511
512
	//==========================================================================
513
    // Returns DB instance or create initial connection 
514
	// 		@param $database_host
515
	// 		@param $database_name
516
	// 		@param $database_username
517
	// 		@param $database_password
518
	// 		@param $db_driver
519
	// 		@param $force_encoding
520
	// 		@param $is_installation
521
	//==========================================================================
522
	public static function GetInstance($database_host = '', $database_name = '', $database_username = '', $database_password = '', $db_driver = '', $force_encoding = false, $is_installation = false, $ssl=false)
523
	{
524
		$database_port = '';
525
		
526
		$host_parts = explode(':', $database_host);		
527
		if(isset($host_parts[1]) && is_numeric($host_parts[1])){
528
			$database_host = $host_parts[0];	
529
			$database_port = $host_parts[1];	
530
		}
531
		
532
		if($database_host == ''){
533
			$config = new Config();	
534
			$database_host = $config->getHost();
535
			$database_name = $config->getDatabase();
536
			$database_username = $config->getUser();
537
			$database_password = $config->getPassword();			
538
			$db_driver = $config->getDatabaseType();
539
		}
540
		
541
		if(!self::$objInstance){
542
			self::$objInstance = new Database($database_host, $database_name, $database_username, $database_password, $db_driver, $force_encoding, $is_installation, $ssl);
543
			self::$objInstance->Open();
544
        }		
545
        return self::$objInstance; 
546
	}
547
	
548
	/**
549
	 * Check if connected
550
	 */
551
	public static function IsConnected()
552
	{
553
		return (self::$objInstance) ? true : false; 
554
	}
555
	
556
	/**
557
	 * Prepare log SQL
558
	 */
559
	private function PrepareLogSQL($e, $query)
560
	{
561
        if(self::$PROJECT == 'AdminPanel'){
562
            $sql_log = '';
563
            $error_no = $e->getCode();
564
            $error_descr  = 'ENV:        '.$_SERVER['SERVER_NAME'].'<br><br>';
565
            $error_descr .= 'TIME:       '.@date('M d, Y g:i A').'<br><br>';
566
            $error_descr .= 'SCRIPT:     '.$_SERVER['PHP_SELF'].'<br><br>';
567
            $error_descr .= 'ERROR LINE: '.(int)$e->getLine().'<br><br>'; 
568
            $error_descr .= 'ERROR:      '.$this->error.'<br><br>';
569
            $error_descr .= 'QUERY:      '.$query.'<br><br>';
570
            $current_file = basename($_SERVER['PHP_SELF'], '.php').'.php';
571
            
572
            $ip_address = get_ip_address();
573
            $sql_log = 'INSERT INTO '.TABLE_SYSTEM_LOGS.' (id, log_type, title, file_name, log, ip_address, date_created)
574
                        VALUES (NULL, \'Error\', \'DB Error #'.$error_no.'\', \''.$current_file.'\', \''.encode_text($error_descr).'\', \''.$ip_address.'\', \''.@date('Y-m-d H:i:s').'\')';
575
            return $sql_log;            
576
        }else{
577
            return '';
578
        }
579
	}
580
	
581
}
582
583