GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

DB   F
last analyzed

Complexity

Total Complexity 164

Size/Duplication

Total Lines 1342
Duplicated Lines 4.62 %

Coupling/Cohesion

Components 3
Dependencies 6

Importance

Changes 0
Metric Value
dl 62
loc 1342
rs 0.8
c 0
b 0
f 0
wmc 164
lcom 3
cbo 6

48 Methods

Rating   Name   Duplication   Size   Complexity  
B getInstance() 0 32 7
A create() 0 4 1
A getSupportedList() 0 5 1
A getEnableList() 21 21 5
A getDisableList() 21 21 5
B _getSupportedList() 0 47 6
A _sortDBMS() 0 27 5
A isSupported() 0 4 1
A isConnected() 0 11 4
A actStart() 0 7 1
B actFinish() 0 70 9
A setQueryLog() 0 4 1
A setError() 0 5 1
A isError() 0 4 1
A getError() 0 5 1
C executeQuery() 12 60 12
A checkQueryCacheFile() 0 20 5
C _executeQuery() 8 60 16
A getCountCache() 0 52 1
A putCountCache() 0 32 1
A resetCountCache() 0 24 1
A dropTable() 0 9 2
B getSelectSql() 0 57 10
A getClickCountQuery() 0 18 2
A getDeleteSql() 0 24 4
A getUpdateSql() 0 24 5
A getInsertSql() 0 8 2
A _getSlaveConnectionStringIndex() 0 6 1
A _getConnection() 0 25 5
A _dbInfoExists() 0 12 3
A _close() 0 4 1
A close() 0 21 3
A _begin() 0 4 1
A begin() 0 13 3
A _rollback() 0 4 1
A rollback() 0 16 5
A _commit() 0 4 1
A commit() 0 16 6
A __query() 0 4 1
A _query() 0 17 2
B _setDBInfo() 0 20 6
A __connect() 0 4 1
A _afterConnect() 0 4 1
B _connect() 0 41 6
A actDBClassStart() 0 6 1
A actDBClassFinish() 0 11 2
A getParser() 0 11 3
A __construct() 0 5 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like DB often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use DB, and based on these observations, apply Extract Interface, too.

1
<?php
2
/* Copyright (C) XEHub <https://www.xehub.io> */
3
4
/**
5
 * - DB parent class
6
 * - usage of db in XE is via xml
7
 * - there are 2 types of xml - query xml, schema xml
8
 * - in case of query xml, DB::executeQuery() method compiles xml file into php code and then execute it
9
 * - query xml has unique query id, and will be created in module
10
 * - queryid = module_name.query_name
11
 *
12
 * @author XEHub ([email protected])
13
 * @package /classes/db
14
 * @version 0.1
15
 */
16
class DB
17
{
18
19
	static $isSupported = FALSE;
20
21
	/**
22
	 * priority of DBMS
23
	 * @var array
24
	 */
25
	var $priority_dbms = array(
26
		'mysqli' => 6,
27
		'mysqli_innodb' => 5,
28
		'mysql' => 4,
29
		'mysql_innodb' => 3,
30
		'cubrid' => 2,
31
		'mssql' => 1
32
	);
33
34
	/**
35
	 * count cache path
36
	 * @var string
37
	 */
38
	var $count_cache_path = 'files/cache/db';
39
40
	/**
41
	 * operations for condition
42
	 * @var array
43
	 */
44
	var $cond_operation = array(
45
		'equal' => '=',
46
		'more' => '>=',
47
		'excess' => '>',
48
		'less' => '<=',
49
		'below' => '<',
50
		'notequal' => '<>',
51
		'notnull' => 'is not null',
52
		'null' => 'is null',
53
	);
54
55
	/**
56
	 * master database connection string
57
	 * @var array
58
	 */
59
	var $master_db = NULL;
60
61
	/**
62
	 * array of slave databases connection strings
63
	 * @var array
64
	 */
65
	var $slave_db = NULL;
66
	var $result = NULL;
67
68
	/**
69
	 * error code (0 means no error)
70
	 * @var int
71
	 */
72
	var $errno = 0;
73
74
	/**
75
	 * error message
76
	 * @var string
77
	 */
78
	var $errstr = '';
79
80
	/**
81
	 * query string of latest executed query
82
	 * @var string
83
	 */
84
	var $query = '';
85
	var $connection = '';
86
87
	/**
88
	 * elapsed time of latest executed query
89
	 * @var int
90
	 */
91
	var $elapsed_time = 0;
92
93
	/**
94
	 * elapsed time of latest executed DB class
95
	 * @var int
96
	 */
97
	var $elapsed_dbclass_time = 0;
98
99
	/**
100
	 * transaction flag
101
	 * @var boolean
102
	 */
103
	var $transaction_started = FALSE;
104
	var $is_connected = FALSE;
105
106
	/**
107
	 * returns enable list in supported dbms list
108
	 * will be written by classes/DB/DB***.class.php
109
	 * @var array
110
	 */
111
	static $supported_list = array();
112
113
	/**
114
	 * location of query cache
115
	 * @var string
116
	 */
117
	var $cache_file = 'files/cache/queries/';
118
119
	/**
120
	 * stores database type: 'mysql','cubrid','mssql' etc. or 'db' when database is not yet set
121
	 * @var string
122
	 */
123
	var $db_type;
124
125
	/**
126
	 * flag to decide if class prepared statements or not (when supported); can be changed from db.config.info
127
	 * @var string
128
	 */
129
	var $use_prepared_statements;
130
131
	/**
132
	 * leve of transaction
133
	 * @var unknown
134
	 */
135
	private $transactionNestedLevel = 0;
136
137
	/**
138
	 * returns instance of certain db type
139
	 * @param string $db_type type of db
140
	 * @return DB return DB object instance
141
	 */
142
	function getInstance($db_type = NULL)
143
	{
144
		if(!$db_type)
0 ignored issues
show
Bug Best Practice introduced by
The expression $db_type of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
145
		{
146
			$db_type = Context::getDBType();
147
		}
148
		if(!$db_type && Context::isInstalled())
149
		{
150
			return new BaseObject(-1, 'msg_db_not_setted');
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \BaseObject(-1, 'msg_db_not_setted'); (BaseObject) is incompatible with the return type documented by DB::getInstance of type DB.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
151
		}
152
153
		if(!isset($GLOBALS['__DB__']))
154
		{
155
			$GLOBALS['__DB__'] = array();
156
		}
157
		if(!isset($GLOBALS['__DB__'][$db_type]))
158
		{
159
			$class_name = 'DB' . ucfirst($db_type);
160
			$class_file = _XE_PATH_ . "classes/db/$class_name.class.php";
161
			if(!file_exists($class_file))
162
			{
163
				return new BaseObject(-1, 'msg_db_not_setted');
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \BaseObject(-1, 'msg_db_not_setted'); (BaseObject) is incompatible with the return type documented by DB::getInstance of type DB.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
164
			}
165
166
			// get a singletone instance of the database driver class
167
			require_once($class_file);
168
			$GLOBALS['__DB__'][$db_type] = call_user_func(array($class_name, 'create'));
169
			$GLOBALS['__DB__'][$db_type]->db_type = $db_type;
170
		}
171
172
		return $GLOBALS['__DB__'][$db_type];
173
	}
174
175
	/**
176
	 * returns instance of db
177
	 * @return DB return DB object instance
178
	 */
179
	function create()
180
	{
181
		return new DB;
182
	}
183
184
	/**
185
	 * constructor
186
	 * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
187
	 */
188
	function __construct()
189
	{
190
		$this->count_cache_path = _XE_PATH_ . $this->count_cache_path;
191
		$this->cache_file = _XE_PATH_ . $this->cache_file;
192
	}
193
194
	/**
195
	 * returns list of supported dbms list
196
	 * this list return by directory list
197
	 * check by instance can creatable
198
	 * @return array return supported DBMS list
199
	 */
200
	function getSupportedList()
201
	{
202
		$oDB = new DB();
203
		return $oDB->_getSupportedList();
204
	}
205
206
	/**
207
	 * returns enable list in supported dbms list
208
	 * this list return by child class
209
	 * @return array return enable DBMS list in supported dbms list
210
	 */
211 View Code Duplication
	public static function getEnableList()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
212
	{
213
		if(!self::$supported_list)
0 ignored issues
show
Bug Best Practice introduced by
The expression self::$supported_list of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
214
		{
215
			$oDB = new DB();
216
			self::$supported_list = $oDB->_getSupportedList();
217
		}
218
219
		$enableList = array();
220
		if(is_array(self::$supported_list))
221
		{
222
			foreach(self::$supported_list AS $key => $value)
223
			{
224
				if($value->enable)
225
				{
226
					$enableList[] = $value;
227
				}
228
			}
229
		}
230
		return $enableList;
231
	}
232
233
	/**
234
	 * returns list of disable in supported dbms list
235
	 * this list return by child class
236
	 * @return array return disable DBMS list in supported dbms list
237
	 */
238 View Code Duplication
	public static function getDisableList()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
239
	{
240
		if(!self::$supported_list)
0 ignored issues
show
Bug Best Practice introduced by
The expression self::$supported_list of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
241
		{
242
			$oDB = new DB();
243
			self::$supported_list = $oDB->_getSupportedList();
244
		}
245
246
		$disableList = array();
247
		if(is_array(self::$supported_list))
248
		{
249
			foreach(self::$supported_list AS $key => $value)
250
			{
251
				if(!$value->enable)
252
				{
253
					$disableList[] = $value;
254
				}
255
			}
256
		}
257
		return $disableList;
258
	}
259
260
	/**
261
	 * returns list of supported dbms list
262
	 * this method is private
263
	 * @return array return supported DBMS list
264
	 */
265
	function _getSupportedList()
266
	{
267
		static $get_supported_list = '';
268
		if(is_array($get_supported_list))
269
		{
270
			self::$supported_list = $get_supported_list;
271
			return self::$supported_list;
272
		}
273
		$get_supported_list = array();
274
		$db_classes_path = _XE_PATH_ . "classes/db/";
275
		$filter = "/^DB([^\.]+)\.class\.php/i";
276
		$supported_list = FileHandler::readDir($db_classes_path, $filter, TRUE);
277
278
		// after creating instance of class, check is supported
279
		for($i = 0; $i < count($supported_list); $i++)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
280
		{
281
			$db_type = $supported_list[$i];
282
283
			$class_name = sprintf("DB%s%s", strtoupper(substr($db_type, 0, 1)), strtolower(substr($db_type, 1)));
284
			$class_file = sprintf(_XE_PATH_ . "classes/db/%s.class.php", $class_name);
285
			if(!file_exists($class_file))
286
			{
287
				continue;
288
			}
289
290
			unset($oDB);
291
			require_once($class_file);
292
			$oDB = new $class_name(FALSE);
293
294
			if(!$oDB)
295
			{
296
				continue;
297
			}
298
299
			$obj = new stdClass;
300
			$obj->db_type = $db_type;
301
			$obj->enable = $oDB->isSupported() ? TRUE : FALSE;
302
303
			$get_supported_list[] = $obj;
304
		}
305
306
		// sort
307
		@usort($get_supported_list, array($this, '_sortDBMS'));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
308
309
		self::$supported_list = $get_supported_list;
310
		return self::$supported_list;
311
	}
312
313
	/**
314
	 * sort dbms as priority
315
	 */
316
	function _sortDBMS($a, $b)
317
	{
318
		if(!isset($this->priority_dbms[$a->db_type]))
319
		{
320
			$priority_a = 0;
321
		}
322
		else
323
		{
324
			$priority_a = $this->priority_dbms[$a->db_type];
325
		}
326
327
		if(!isset($this->priority_dbms[$b->db_type]))
328
		{
329
			$priority_b = 0;
330
		}
331
		else
332
		{
333
			$priority_b = $this->priority_dbms[$b->db_type];
334
		}
335
336
		if($priority_a == $priority_b)
337
		{
338
			return 0;
339
		}
340
341
		return ($priority_a > $priority_b) ? -1 : 1;
342
	}
343
344
	/**
345
	 * Return dbms supportable status
346
	 * The value is set in the child class
347
	 * @return boolean true: is supported, false: is not supported
348
	 */
349
	function isSupported()
350
	{
351
		return self::$isSupported;
352
	}
353
354
	/**
355
	 * Return connected status
356
	 * @param string $type master or slave
357
	 * @param int $indx key of server list
358
	 * @return boolean true: connected, false: not connected
359
	 */
360
	function isConnected($type = 'master', $indx = 0)
361
	{
362
		if($type == 'master')
363
		{
364
			return $this->master_db["is_connected"] ? TRUE : FALSE;
365
		}
366
		else
367
		{
368
			return $this->slave_db[$indx]["is_connected"] ? TRUE : FALSE;
369
		}
370
	}
371
372
	/**
373
	 * start recording log
374
	 * @param string $query query string
375
	 * @return void
376
	 */
377
	function actStart($query)
378
	{
379
		$this->setError(0, 'success');
380
		$this->query = $query;
381
		$this->act_start = getMicroTime();
0 ignored issues
show
Bug introduced by
The property act_start does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
382
		$this->elapsed_time = 0;
383
	}
384
385
	/**
386
	 * finish recording log
387
	 * @return void
388
	 */
389
	function actFinish()
390
	{
391
		if(!$this->query)
392
		{
393
			return;
394
		}
395
		$this->act_finish = getMicroTime();
0 ignored issues
show
Bug introduced by
The property act_finish does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
396
		$elapsed_time = $this->act_finish - $this->act_start;
397
		$this->elapsed_time = $elapsed_time;
0 ignored issues
show
Documentation Bug introduced by
The property $elapsed_time was declared of type integer, but $elapsed_time is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
398
		$GLOBALS['__db_elapsed_time__'] += $elapsed_time;
399
400
		$site_module_info = Context::get('site_module_info');
401
		$log = array();
402
		$log['query'] = $this->query;
403
		$log['elapsed_time'] = $elapsed_time;
404
		$log['connection'] = $this->connection;
405
		$log['query_id'] = $this->query_id;
0 ignored issues
show
Bug introduced by
The property query_id does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
406
		$log['module'] = $site_module_info->module;
407
		$log['act'] = Context::get('act');
408
		$log['time'] = date('Y-m-d H:i:s');
409
410
		$bt = version_compare(PHP_VERSION, '5.3.6', '>=') ? debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS) : debug_backtrace();
411
412
		foreach($bt as $no => $call)
413
		{
414
			if($call['function'] == 'executeQuery' || $call['function'] == 'executeQueryArray')
415
			{
416
				$call_no = $no;
417
				$call_no++;
418
				$log['called_file'] = $bt[$call_no]['file'].':'.$bt[$call_no]['line'];
419
				$log['called_file'] = str_replace(_XE_PATH_ , '', $log['called_file']);
420
				$call_no++;
421
				$log['called_method'] = $bt[$call_no]['class'].$bt[$call_no]['type'].$bt[$call_no]['function'];
422
				break;
423
			}
424
		}
425
426
		// leave error log if an error occured (if __DEBUG_DB_OUTPUT__ is defined)
427
		if($this->isError())
428
		{
429
			$log['result'] = 'Failed';
430
			$log['errno'] = $this->errno;
431
			$log['errstr'] = $this->errstr;
432
433
			if(__DEBUG_DB_OUTPUT__ == 1)
434
			{
435
				$debug_file = _XE_PATH_ . "files/_debug_db_query.php";
436
				$buff = array();
437
				if(!file_exists($debug_file))
438
				{
439
					$buff[] = '<?php exit(); ?' . '>';
440
				}
441
				$buff[] = print_r($log, TRUE);
442
				@file_put_contents($debug_file, implode("\n", $buff) . "\n\n", FILE_APPEND|LOCK_EX);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
443
			}
444
		}
445
		else
446
		{
447
			$log['result'] = 'Success';
448
		}
449
450
		$this->setQueryLog($log);
451
452
		$log_args = new stdClass;
453
		$log_args->query = $this->query;
454
		$log_args->query_id = $this->query_id;
455
		$log_args->caller = $log['called_method'] . '() in ' . $log['called_file'];
456
		$log_args->connection = $log['connection'];
457
		writeSlowlog('query', $elapsed_time, $log_args);
458
	}
459
460
	/**
461
	 * set query debug log
462
	 * @param array $log values set query debug
463
	 * @return void
464
	*/
465
	function setQueryLog($log)
466
	{
467
		$GLOBALS['__db_queries__'][] = $log;
468
	}
469
470
	/**
471
	 * set error
472
	 * @param int $errno error code
473
	 * @param string $errstr error message
474
	 * @return void
475
	 */
476
	function setError($errno = 0, $errstr = 'success')
477
	{
478
		$this->errno = $errno;
479
		$this->errstr = $errstr;
480
	}
481
482
	/**
483
	 * Return error status
484
	 * @return boolean true: error, false: no error
485
	 */
486
	function isError()
487
	{
488
		return ($this->errno !== 0);
489
	}
490
491
	/**
492
	 * Returns object of error info
493
	 * @return object object of error
494
	 */
495
	function getError()
496
	{
497
		$this->errstr = Context::convertEncodingStr($this->errstr);
498
		return new BaseObject($this->errno, $this->errstr);
499
	}
500
501
	/**
502
	 * Execute Query that result of the query xml file
503
	 * This function finds xml file or cache file of $query_id, compiles it and then execute it
504
	 * @param string $query_id query id (module.queryname)
505
	 * @param array|object $args arguments for query
506
	 * @param array $arg_columns column list. if you want get specific colums from executed result, add column list to $arg_columns
507
	 * @return object result of query
508
	 */
509
	function executeQuery($query_id, $args = NULL, $arg_columns = NULL, $type = NULL)
510
	{
511
		static $cache_file = array();
512
513
		if(!$query_id)
514
		{
515
			return new BaseObject(-1, 'msg_invalid_queryid');
516
		}
517
		if(!$this->db_type)
518
		{
519
			return;
520
		}
521
522
		$this->actDBClassStart();
523
524
		$this->query_id = $query_id;
525
526
		if(!isset($cache_file[$query_id]) || !file_exists($cache_file[$query_id]))
527
		{
528
			$id_args = explode('.', $query_id);
529
			if(count($id_args) == 2)
530
			{
531
				$target = 'modules';
532
				$module = $id_args[0];
533
				$id = $id_args[1];
534
			}
535 View Code Duplication
			elseif(count($id_args) == 3)
536
			{
537
				$target = $id_args[0];
538
				$typeList = array('addons' => 1, 'widgets' => 1);
539
				if(!isset($typeList[$target]))
540
				{
541
					$this->actDBClassFinish();
542
					return;
543
				}
544
				$module = $id_args[1];
545
				$id = $id_args[2];
546
			}
547
			if(!$target || !$module || !$id)
0 ignored issues
show
Bug introduced by
The variable $target does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $module does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $id does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
548
			{
549
				$this->actDBClassFinish();
550
				return new BaseObject(-1, 'msg_invalid_queryid');
551
			}
552
553
			$xml_file = sprintf('%s%s/%s/queries/%s.xml', _XE_PATH_, $target, $module, $id);
554
			if(!file_exists($xml_file))
555
			{
556
				$this->actDBClassFinish();
557
				return new BaseObject(-1, 'msg_invalid_queryid');
558
			}
559
560
			// look for cache file
561
			$cache_file[$query_id] = $this->checkQueryCacheFile($query_id, $xml_file);
562
		}
563
		$result = $this->_executeQuery($cache_file[$query_id], $args, $query_id, $arg_columns, $type);
0 ignored issues
show
Bug introduced by
It seems like $args defined by parameter $args on line 509 can also be of type null; however, DB::_executeQuery() does only seem to accept array|object, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
Bug introduced by
It seems like $arg_columns defined by parameter $arg_columns on line 509 can also be of type null; however, DB::_executeQuery() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
564
565
		$this->actDBClassFinish();
566
		// execute query
567
		return $result;
568
	}
569
570
	/**
571
	 * Look for query cache file
572
	 * @param string $query_id query id for finding
573
	 * @param string $xml_file original xml query file
574
	 * @return string cache file
575
	 */
576
	function checkQueryCacheFile($query_id, $xml_file)
577
	{
578
		// first try finding cache file
579
		$cache_file = sprintf('%s%s%s.%s.%s.cache.php', _XE_PATH_, $this->cache_file, $query_id, __ZBXE_VERSION__, $this->db_type);
0 ignored issues
show
Deprecated Code introduced by
The constant __ZBXE_VERSION__ has been deprecated with message: __ZBXE_VERSION__ will be removed. Use __XE_VERSION__ instead.

This class constant has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
580
581
		$cache_time = -1;
582
		if(file_exists($cache_file))
583
		{
584
			$cache_time = filemtime($cache_file);
585
		}
586
587
		// if there is no cache file or is not new, find original xml query file and parse it
588
		if($cache_time < filemtime($xml_file) || $cache_time < filemtime(_XE_PATH_ . 'classes/db/DB.class.php') || $cache_time < filemtime(_XE_PATH_ . 'classes/xml/XmlQueryParser.class.php'))
589
		{
590
			$oParser = new XmlQueryParser();
591
			$oParser->parse($query_id, $xml_file, $cache_file);
592
		}
593
594
		return $cache_file;
595
	}
596
597
	/**
598
	 * Execute query and return the result
599
	 * @param string $cache_file cache file of query
600
	 * @param array|object $source_args arguments for query
601
	 * @param string $query_id query id
602
	 * @param array $arg_columns column list. if you want get specific colums from executed result, add column list to $arg_columns
603
	 * @return object result of query
604
	 */
605
	function _executeQuery($cache_file, $source_args, $query_id, $arg_columns, $type)
606
	{
607
		global $lang;
608
		
609
		if(!in_array($type, array('master','slave'))) $type = 'slave';
610
611
		if(!file_exists($cache_file))
612
		{
613
			return new BaseObject(-1, 'msg_invalid_queryid');
614
		}
615
616
		if($source_args)
617
		{
618
			$args = clone $source_args;
619
		}
620
621
		$output = include($cache_file);
622
623 View Code Duplication
		if((is_a($output, 'BaseObject') || is_subclass_of($output, 'BaseObject')) && !$output->toBool())
624
		{
625
			return $output;
626
		}
627
628
		// execute appropriate query
629
		switch($output->getAction())
630
		{
631
			case 'insert' :
632
			case 'insert-select' :
633
				$this->resetCountCache($output->tables);
0 ignored issues
show
Unused Code introduced by
The call to the method DB::resetCountCache() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
634
				$output = $this->_executeInsertAct($output);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class DB as the method _executeInsertAct() does only exist in the following sub-classes of DB: DBCubrid, DBCubridConnectWrapper, DBMssql, DBMssqlConnectWrapper, DBMysql, DBMysqlConnectWrapper, DBMysql_innodb, DBMysqli, DBMysqliConnectWrapper, DBMysqli_innodb. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
635
				break;
636
			case 'update' :
637
				$this->resetCountCache($output->tables);
0 ignored issues
show
Unused Code introduced by
The call to the method DB::resetCountCache() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
638
				$output = $this->_executeUpdateAct($output);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class DB as the method _executeUpdateAct() does only exist in the following sub-classes of DB: DBCubrid, DBCubridConnectWrapper, DBMssql, DBMssqlConnectWrapper, DBMysql, DBMysqlConnectWrapper, DBMysql_innodb, DBMysqli, DBMysqliConnectWrapper, DBMysqli_innodb. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
639
				break;
640
			case 'delete' :
641
				$this->resetCountCache($output->tables);
0 ignored issues
show
Unused Code introduced by
The call to the method DB::resetCountCache() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
642
				$output = $this->_executeDeleteAct($output);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class DB as the method _executeDeleteAct() does only exist in the following sub-classes of DB: DBCubrid, DBCubridConnectWrapper, DBMssql, DBMssqlConnectWrapper, DBMysql, DBMysqlConnectWrapper, DBMysql_innodb, DBMysqli, DBMysqliConnectWrapper, DBMysqli_innodb. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
643
				break;
644
			case 'select' :
645
				$arg_columns = is_array($arg_columns) ? $arg_columns : array();
646
				$output->setColumnList($arg_columns);
647
				$connection = $this->_getConnection($type);
648
				$output = $this->_executeSelectAct($output, $connection);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class DB as the method _executeSelectAct() does only exist in the following sub-classes of DB: DBCubrid, DBCubridConnectWrapper, DBMssql, DBMssqlConnectWrapper, DBMysql, DBMysqlConnectWrapper, DBMysql_innodb, DBMysqli, DBMysqliConnectWrapper, DBMysqli_innodb. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
649
				break;
650
		}
651
652
		if($this->isError())
653
		{
654
			$output = $this->getError();
655
		}
656 View Code Duplication
		else if(!is_a($output, 'BaseObject') && !is_subclass_of($output, 'BaseObject'))
657
		{
658
			$output = new BaseObject();
659
		}
660
		$output->add('_query', $this->query);
661
		$output->add('_elapsed_time', sprintf("%0.5f", $this->elapsed_time));
662
663
		return $output;
664
	}
665
666
	/**
667
	 * Returns counter cache data
668
	 * @param array|string $tables tables to get data
669
	 * @param string $condition condition to get data
670
	 * @return int count of cache data
671
	 */
672
	function getCountCache($tables, $condition)
0 ignored issues
show
Unused Code introduced by
The parameter $tables is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $condition is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
673
	{
674
		return FALSE;
675
/*
676
		if(!$tables)
677
		{
678
			return FALSE;
679
		}
680
		if(!is_dir($this->count_cache_path))
681
		{
682
			return FileHandler::makeDir($this->count_cache_path);
683
		}
684
685
		$condition = md5($condition);
686
687
		if(!is_array($tables))
688
		{
689
			$tables_str = $tables;
690
		}
691
		else
692
		{
693
			$tables_str = implode('.', $tables);
694
		}
695
696
		$cache_path = sprintf('%s/%s%s', $this->count_cache_path, $this->prefix, $tables_str);
697
		FileHandler::makeDir($cache_path);
698
699
		$cache_filename = sprintf('%s/%s.%s', $cache_path, $tables_str, $condition);
700
		if(!file_exists($cache_filename))
701
		{
702
			return FALSE;
703
		}
704
705
		$cache_mtime = filemtime($cache_filename);
706
707
		if(!is_array($tables))
708
		{
709
			$tables = array($tables);
710
		}
711
		foreach($tables as $alias => $table)
712
		{
713
			$table_filename = sprintf('%s/cache.%s%s', $this->count_cache_path, $this->prefix, $table);
714
			if(!file_exists($table_filename) || filemtime($table_filename) > $cache_mtime)
715
			{
716
				return FALSE;
717
			}
718
		}
719
720
		$count = (int) FileHandler::readFile($cache_filename);
721
		return $count;
722
*/
723
	}
724
725
	/**
726
	 * Save counter cache data
727
	 * @param array|string $tables tables to save data
728
	 * @param string $condition condition to save data
729
	 * @param int $count count of cache data to save
730
	 * @return void
731
	 */
732
	function putCountCache($tables, $condition, $count = 0)
0 ignored issues
show
Unused Code introduced by
The parameter $tables is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $condition is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $count is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
733
	{
734
		return FALSE;
735
/*
736
		if(!$tables)
737
		{
738
			return FALSE;
739
		}
740
		if(!is_dir($this->count_cache_path))
741
		{
742
			return FileHandler::makeDir($this->count_cache_path);
743
		}
744
745
		$condition = md5($condition);
746
747
		if(!is_array($tables))
748
		{
749
			$tables_str = $tables;
750
		}
751
		else
752
		{
753
			$tables_str = implode('.', $tables);
754
		}
755
756
		$cache_path = sprintf('%s/%s%s', $this->count_cache_path, $this->prefix, $tables_str);
757
		FileHandler::makeDir($cache_path);
758
759
		$cache_filename = sprintf('%s/%s.%s', $cache_path, $tables_str, $condition);
760
761
		FileHandler::writeFile($cache_filename, $count);
762
*/
763
	}
764
765
	/**
766
	 * Reset counter cache data
767
	 * @param array|string $tables tables to reset cache data
768
	 * @return boolean true: success, false: failed
769
	 */
770
	function resetCountCache($tables)
0 ignored issues
show
Unused Code introduced by
The parameter $tables is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
771
	{
772
		return FALSE;
773
/*
774
		if(!$tables)
775
		{
776
			return FALSE;
777
		}
778
		return FileHandler::makeDir($this->count_cache_path);
779
780
		if(!is_array($tables))
781
		{
782
			$tables = array($tables);
783
		}
784
		foreach($tables as $alias => $table)
785
		{
786
			$filename = sprintf('%s/cache.%s%s', $this->count_cache_path, $this->prefix, $table);
787
			FileHandler::removeFile($filename);
788
			FileHandler::writeFile($filename, '');
789
		}
790
791
		return TRUE;
792
 */
793
	}
794
795
	/**
796
	 * Drop tables
797
	 * @param string $table_name
798
	 * @return void
799
	 */
800
	function dropTable($table_name)
801
	{
802
		if(!$table_name)
803
		{
804
			return;
805
		}
806
		$query = sprintf("drop table %s%s", $this->prefix, $table_name);
0 ignored issues
show
Bug introduced by
The property prefix does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
807
		$this->_query($query);
808
	}
809
810
	/**
811
	 * Return select query string
812
	 * @param object $query
813
	 * @param boolean $with_values
814
	 * @return string
815
	 */
816
	function getSelectSql($query, $with_values = TRUE)
817
	{
818
		$select = $query->getSelectString($with_values);
819
		if($select == '')
820
		{
821
			return new BaseObject(-1, "Invalid query");
822
		}
823
		$select = 'SELECT ' . $select;
824
825
		$from = $query->getFromString($with_values);
826
		if($from == '')
827
		{
828
			return new BaseObject(-1, "Invalid query");
829
		}
830
		$from = ' FROM ' . $from;
831
832
		$where = $query->getWhereString($with_values);
833
		if($where != '')
834
		{
835
			$where = ' WHERE ' . $where;
836
		}
837
838
		$tableObjects = $query->getTables();
839
		$index_hint_list = '';
840
		foreach($tableObjects as $tableObject)
841
		{
842
			if(is_a($tableObject, 'CubridTableWithHint'))
843
			{
844
				$index_hint_list .= $tableObject->getIndexHintString() . ', ';
845
			}
846
		}
847
		$index_hint_list = substr($index_hint_list, 0, -2);
848
		if($index_hint_list != '')
849
		{
850
			$index_hint_list = 'USING INDEX ' . $index_hint_list;
851
		}
852
853
		$groupBy = $query->getGroupByString();
854
		if($groupBy != '')
855
		{
856
			$groupBy = ' GROUP BY ' . $groupBy;
857
		}
858
859
		$orderBy = $query->getOrderByString();
860
		if($orderBy != '')
861
		{
862
			$orderBy = ' ORDER BY ' . $orderBy;
863
		}
864
865
		$limit = $query->getLimitString();
866
		if($limit != '')
867
		{
868
			$limit = ' LIMIT ' . $limit;
869
		}
870
871
		return $select . ' ' . $from . ' ' . $where . ' ' . $index_hint_list . ' ' . $groupBy . ' ' . $orderBy . ' ' . $limit;
872
	}
873
874
	/**
875
	 * Given a SELECT statement that uses click count
876
	 * returns the corresponding update sql string
877
	 * for databases that don't have click count support built in
878
	 * (aka all besides CUBRID)
879
	 *
880
	 * Function does not check if click count columns exist!
881
	 * You must call $query->usesClickCount() before using this function
882
	 *
883
	 * @param $queryObject
884
	 */
885
	function getClickCountQuery($queryObject)
886
	{
887
		$new_update_columns = array();
888
		$click_count_columns = $queryObject->getClickCountColumns();
889
		foreach($click_count_columns as $click_count_column)
890
		{
891
			$click_count_column_name = $click_count_column->column_name;
892
893
			$increase_by_1 = new Argument($click_count_column_name, null);
894
			$increase_by_1->setColumnOperation('+');
895
			$increase_by_1->ensureDefaultValue(1);
896
897
			$update_expression = new UpdateExpression($click_count_column_name, $increase_by_1);
898
			$new_update_columns[] = $update_expression;
899
		}
900
		$queryObject->columns = $new_update_columns;
901
		return $queryObject;
902
	}
903
904
	/**
905
	 * Return delete query string
906
	 * @param object $query
907
	 * @param boolean $with_values
908
	 * @param boolean $with_priority
909
	 * @return string
910
	 */
911
	function getDeleteSql($query, $with_values = TRUE, $with_priority = FALSE)
912
	{
913
		$sql = 'DELETE ';
914
915
		$sql .= $with_priority ? $query->getPriority() : '';
916
		$tables = $query->getTables();
917
918
		$sql .= $tables[0]->getAlias();
919
920
		$from = $query->getFromString($with_values);
921
		if($from == '')
922
		{
923
			return new BaseObject(-1, "Invalid query");
924
		}
925
		$sql .= ' FROM ' . $from;
926
927
		$where = $query->getWhereString($with_values);
928
		if($where != '')
929
		{
930
			$sql .= ' WHERE ' . $where;
931
		}
932
933
		return $sql;
934
	}
935
936
	/**
937
	 * Return update query string
938
	 * @param object $query
939
	 * @param boolean $with_values
940
	 * @param boolean $with_priority
941
	 * @return string
942
	 */
943
	function getUpdateSql($query, $with_values = TRUE, $with_priority = FALSE)
944
	{
945
		$columnsList = $query->getUpdateString($with_values);
946
		if($columnsList == '')
947
		{
948
			return new BaseObject(-1, "Invalid query");
949
		}
950
951
		$tables = $query->getFromString($with_values);
952
		if($tables == '')
953
		{
954
			return new BaseObject(-1, "Invalid query");
955
		}
956
957
		$where = $query->getWhereString($with_values);
958
		if($where != '')
959
		{
960
			$where = ' WHERE ' . $where;
961
		}
962
963
		$priority = $with_priority ? $query->getPriority() : '';
964
965
		return "UPDATE $priority $tables SET $columnsList " . $where;
966
	}
967
968
	/**
969
	 * Return insert query string
970
	 * @param object $query
971
	 * @param boolean $with_values
972
	 * @param boolean $with_priority
973
	 * @return string
974
	 */
975
	function getInsertSql($query, $with_values = TRUE, $with_priority = FALSE)
976
	{
977
		$tableName = $query->getFirstTableName();
978
		$values = $query->getInsertString($with_values);
979
		$priority = $with_priority ? $query->getPriority() : '';
980
981
		return "INSERT $priority INTO $tableName \n $values";
982
	}
983
984
	/**
985
	 * Return index from slave server list
986
	 * @return int
987
	 */
988
	function _getSlaveConnectionStringIndex()
989
	{
990
		$max = count($this->slave_db);
991
		$indx = rand(0, $max - 1);
992
		return $indx;
993
	}
994
995
	/**
996
	 * Return connection resource
997
	 * @param string $type use 'master' or 'slave'. default value is 'master'
998
	 * @param int $indx if indx value is NULL, return rand number in slave server list
999
	 * @return resource
1000
	 */
1001
	function _getConnection($type = 'master', $indx = NULL)
1002
	{
1003
		if($type == 'master')
1004
		{
1005
			if(!$this->master_db['is_connected'])
1006
			{
1007
				$this->_connect($type);
1008
			}
1009
			$this->connection = 'Master ' . $this->master_db['db_hostname'];
1010
			return $this->master_db["resource"];
1011
		}
1012
1013
		if($indx === NULL)
1014
		{
1015
			$indx = $this->_getSlaveConnectionStringIndex($type);
0 ignored issues
show
Unused Code introduced by
The call to DB::_getSlaveConnectionStringIndex() has too many arguments starting with $type.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
1016
		}
1017
1018
		if(!$this->slave_db[$indx]['is_connected'])
1019
		{
1020
			$this->_connect($type, $indx);
1021
		}
1022
1023
		$this->connection = 'Slave ' . $this->slave_db[$indx]['db_hostname'];
1024
		return $this->slave_db[$indx]["resource"];
1025
	}
1026
1027
	/**
1028
	 * check db information exists
1029
	 * @return boolean
1030
	 */
1031
	function _dbInfoExists()
1032
	{
1033
		if(!$this->master_db)
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->master_db of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1034
		{
1035
			return FALSE;
1036
		}
1037
		if(count($this->slave_db) === 0)
1038
		{
1039
			return FALSE;
1040
		}
1041
		return TRUE;
1042
	}
1043
1044
	/**
1045
	 * DB disconnection
1046
	 * this method is protected
1047
	 * @param resource $connection
1048
	 * @return void
1049
	 */
1050
	function _close($connection)
1051
	{
1052
1053
	}
1054
1055
	/**
1056
	 * DB disconnection
1057
	 * @param string $type 'master' or 'slave'
1058
	 * @param int $indx number in slave dbms server list
1059
	 * @return void
1060
	 */
1061
	function close($type = 'master', $indx = 0)
1062
	{
1063
		if(!$this->isConnected($type, $indx))
1064
		{
1065
			return;
1066
		}
1067
1068
		if($type == 'master')
1069
		{
1070
			$connection = &$this->master_db;
1071
		}
1072
		else
1073
		{
1074
			$connection = &$this->slave_db[$indx];
1075
		}
1076
1077
		$this->commit();
1078
		$this->_close($connection["resource"]);
1079
1080
		$connection["is_connected"] = FALSE;
1081
	}
1082
1083
	/**
1084
	 * DB transaction start
1085
	 * this method is protected
1086
	 * @return boolean
1087
	 */
1088
	function _begin($transactionLevel = 0)
1089
	{
1090
		return TRUE;
1091
	}
1092
1093
	/**
1094
	 * DB transaction start
1095
	 * @return void
1096
	 */
1097
	function begin()
1098
	{
1099
		if(!$this->isConnected())
1100
		{
1101
			return;
1102
		}
1103
1104
		if($this->_begin($this->transactionNestedLevel))
1105
		{
1106
			$this->transaction_started = TRUE;
1107
			$this->transactionNestedLevel++;
1108
		}
1109
	}
1110
1111
	/**
1112
	 * DB transaction rollback
1113
	 * this method is protected
1114
	 * @return boolean
1115
	 */
1116
	function _rollback($transactionLevel = 0)
1117
	{
1118
		return TRUE;
1119
	}
1120
1121
	/**
1122
	 * DB transaction rollback
1123
	 * @return void
1124
	 */
1125
	function rollback()
1126
	{
1127
		if(!$this->isConnected() || !$this->transaction_started)
1128
		{
1129
			return;
1130
		}
1131
		if($this->_rollback($this->transactionNestedLevel))
1132
		{
1133
			$this->transactionNestedLevel--;
1134
1135
			if(!$this->transactionNestedLevel)
1136
			{
1137
				$this->transaction_started = FALSE;
1138
			}
1139
		}
1140
	}
1141
1142
	/**
1143
	 * DB transaction commit
1144
	 * this method is protected
1145
	 * @return boolean
1146
	 */
1147
	function _commit()
1148
	{
1149
		return TRUE;
1150
	}
1151
1152
	/**
1153
	 * DB transaction commit
1154
	 * @param boolean $force regardless transaction start status or connect status, forced to commit
1155
	 * @return void
1156
	 */
1157
	function commit($force = FALSE)
1158
	{
1159
		if(!$force && (!$this->isConnected() || !$this->transaction_started))
1160
		{
1161
			return;
1162
		}
1163
		if($this->transactionNestedLevel == 1 && $this->_commit())
1164
		{
1165
			$this->transaction_started = FALSE;
1166
			$this->transactionNestedLevel = 0;
0 ignored issues
show
Documentation Bug introduced by
It seems like 0 of type integer is incompatible with the declared type object<unknown> of property $transactionNestedLevel.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1167
		}
1168
		else
1169
		{
1170
			$this->transactionNestedLevel--;
1171
		}
1172
	}
1173
1174
	/**
1175
	 * Execute the query
1176
	 * this method is protected
1177
	 * @param string $query
1178
	 * @param resource $connection
1179
	 * @return void
1180
	 */
1181
	function __query($query, $connection)
1182
	{
1183
1184
	}
1185
1186
	/**
1187
	 * Execute the query
1188
	 * this method is protected
1189
	 * @param string $query
1190
	 * @param resource $connection
1191
	 * @return resource
1192
	 */
1193
	function _query($query, $connection = NULL)
1194
	{
1195
		if($connection == NULL)
1196
		{
1197
			$connection = $this->_getConnection('master');
1198
		}
1199
		// Notify to start a query execution
1200
		$this->actStart($query);
1201
1202
		// Run the query statement
1203
		$result = $this->__query($query, $connection);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $result is correct as $this->__query($query, $connection) (which targets DB::__query()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1204
1205
		// Notify to complete a query execution
1206
		$this->actFinish();
1207
		// Return result
1208
		return $result;
1209
	}
1210
1211
	/**
1212
	 * DB info settings
1213
	 * this method is protected
1214
	 * @return void
1215
	 */
1216
	function _setDBInfo()
1217
	{
1218
		$db_info = Context::getDBInfo();
1219
		$this->master_db = $db_info->master_db;
1220
		if($db_info->master_db["db_hostname"] == $db_info->slave_db[0]["db_hostname"]
1221
				&& $db_info->master_db["db_port"] == $db_info->slave_db[0]["db_port"]
1222
				&& $db_info->master_db["db_userid"] == $db_info->slave_db[0]["db_userid"]
1223
				&& $db_info->master_db["db_password"] == $db_info->slave_db[0]["db_password"]
1224
				&& $db_info->master_db["db_database"] == $db_info->slave_db[0]["db_database"]
1225
		)
1226
		{
1227
			$this->slave_db[0] = &$this->master_db;
1228
		}
1229
		else
1230
		{
1231
			$this->slave_db = $db_info->slave_db;
1232
		}
1233
		$this->prefix = $db_info->master_db["db_table_prefix"];
1234
		$this->use_prepared_statements = $db_info->use_prepared_statements;
1235
	}
1236
1237
	/**
1238
	 * DB Connect
1239
	 * this method is protected
1240
	 * @param array $connection
1241
	 * @return void
1242
	 */
1243
	function __connect($connection)
1244
	{
1245
1246
	}
1247
1248
	/**
1249
	 * If have a task after connection, add a taks in this method
1250
	 * this method is protected
1251
	 * @param resource $connection
1252
	 * @return void
1253
	 */
1254
	function _afterConnect($connection)
1255
	{
1256
1257
	}
1258
1259
	/**
1260
	 * DB Connect
1261
	 * this method is protected
1262
	 * @param string $type 'master' or 'slave'
1263
	 * @param int $indx number in slave dbms server list
1264
	 * @return void
1265
	 */
1266
	function _connect($type = 'master', $indx = 0)
1267
	{
1268
		if($this->isConnected($type, $indx))
1269
		{
1270
			return;
1271
		}
1272
1273
		// Ignore if no DB information exists
1274
		if(!$this->_dbInfoExists())
1275
		{
1276
			return;
1277
		}
1278
1279
		if($type == 'master')
1280
		{
1281
			$connection = &$this->master_db;
1282
		}
1283
		else
1284
		{
1285
			$connection = &$this->slave_db[$indx];
1286
		}
1287
1288
		$result = $this->__connect($connection);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $result is correct as $this->__connect($connection) (which targets DB::__connect()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1289
		if($result === NULL || $result === FALSE)
1290
		{
1291
			$connection["is_connected"] = FALSE;
1292
			return;
1293
		}
1294
1295
		// Check connections
1296
		$connection["resource"] = $result;
1297
		$connection["is_connected"] = TRUE;
1298
1299
		// Save connection info for db logs
1300
		$this->connection = ucfirst($type) . ' ' . $connection["db_hostname"];
1301
1302
		// regist $this->close callback
1303
		register_shutdown_function(array($this, "close"));
1304
1305
		$this->_afterConnect($result);
0 ignored issues
show
Documentation introduced by
$result is of type null, but the function expects a resource.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1306
	}
1307
1308
	/**
1309
	 * Start recording DBClass log
1310
	 * @return void
1311
	 */
1312
	function actDBClassStart()
1313
	{
1314
		$this->setError(0, 'success');
1315
		$this->act_dbclass_start = getMicroTime();
0 ignored issues
show
Bug introduced by
The property act_dbclass_start does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
1316
		$this->elapsed_dbclass_time = 0;
1317
	}
1318
1319
	/**
1320
	 * Finish recording DBClass log
1321
	 * @return void
1322
	 */
1323
	function actDBClassFinish()
1324
	{
1325
		if(!$this->query)
1326
		{
1327
			return;
1328
		}
1329
		$this->act_dbclass_finish = getMicroTime();
0 ignored issues
show
Bug introduced by
The property act_dbclass_finish does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
1330
		$elapsed_dbclass_time = $this->act_dbclass_finish - $this->act_dbclass_start;
1331
		$this->elapsed_dbclass_time = $elapsed_dbclass_time;
0 ignored issues
show
Documentation Bug introduced by
The property $elapsed_dbclass_time was declared of type integer, but $elapsed_dbclass_time is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1332
		$GLOBALS['__dbclass_elapsed_time__'] += $elapsed_dbclass_time;
1333
	}
1334
1335
	/**
1336
	 * Returns a database specific parser instance
1337
	 * used for escaping expressions and table/column identifiers
1338
	 *
1339
	 * Requires an implementation of the DB class (won't work if database is not set)
1340
	 * this method is singleton
1341
	 *
1342
	 * @param boolean $force force load DBParser instance
1343
	 * @return DBParser
1344
	 */
1345
	function getParser($force = FALSE)
1346
	{
1347
		static $dbParser = NULL;
1348
		if(!$dbParser || $force)
1349
		{
1350
			$oDB = DB::getInstance();
1351
			$dbParser = $oDB->getParser();
1352
		}
1353
1354
		return $dbParser;
1355
	}
1356
1357
}
1358
/* End of file DB.class.php */
1359
/* Location: ./classes/db/DB.class.php */
1360