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.
Completed
Push — develop ( baac3d...439f66 )
by gyeong-won
17:54
created

DB   D

Complexity

Total Complexity 166

Size/Duplication

Total Lines 1346
Duplicated Lines 4.9 %

Coupling/Cohesion

Components 2
Dependencies 6

Importance

Changes 3
Bugs 1 Features 0
Metric Value
dl 66
loc 1346
rs 4
c 3
b 1
f 0
wmc 166
lcom 2
cbo 6

48 Methods

Rating   Name   Duplication   Size   Complexity  
B getEnableList() 23 23 6
B getDisableList() 23 23 6
C getInstance() 0 32 7
A create() 0 4 1
A DB() 0 5 1
A getSupportedList() 0 5 1
B _getSupportedList() 0 47 6
B _sortDBMS() 0 27 5
A isSupported() 0 4 1
A isConnected() 0 11 4
A actStart() 0 7 1
C 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
B checkQueryCacheFile() 0 20 5
C _executeQuery() 8 60 16
A getCountCache() 0 52 1
B putCountCache() 0 32 1
B resetCountCache() 0 24 1
A dropTable() 0 9 2
C getSelectSql() 0 57 10
A getClickCountQuery() 0 18 2
B getDeleteSql() 0 24 4
B getUpdateSql() 0 24 5
A getInsertSql() 0 8 2
A _getSlaveConnectionStringIndex() 0 6 1
B _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
B rollback() 0 16 5
A _commit() 0 4 1
B 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

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) NAVER <http://www.navercorp.com> */
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 NAVER ([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
	var $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 Object(-1, 'msg_db_not_setted');
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Object(-1, 'msg_db_not_setted'); (Object) 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 Object(-1, 'msg_db_not_setted');
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Object(-1, 'msg_db_not_setted'); (Object) 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
187
	 */
188
	function DB()
0 ignored issues
show
Coding Style Best Practice introduced by
Please use __construct() instead of a PHP4-style constructor that is named after the class.
Loading history...
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
	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
		is_a($this, 'DB') ? $self = $this : $self = self::getInstance();
214
		
215
		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...
216
		{
217
			$oDB = new DB();
218
			$self->supported_list = $oDB->_getSupportedList();
219
		}
220
221
		$enableList = array();
222
		if(is_array($self->supported_list))
223
		{
224
			foreach($self->supported_list AS $key => $value)
225
			{
226
				if($value->enable)
227
				{
228
					$enableList[] = $value;
229
				}
230
			}
231
		}
232
		return $enableList;
233
	}
234
235
	/**
236
	 * returns list of disable in supported dbms list
237
	 * this list return by child class
238
	 * @return array return disable DBMS list in supported dbms list
239
	 */
240 View Code Duplication
	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...
241
	{
242
		is_a($this, 'DB') ? $self = $this : $self = self::getInstance();
243
		
244
		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...
245
		{
246
			$oDB = new DB();
247
			$self->supported_list = $oDB->_getSupportedList();
248
		}
249
250
		$disableList = array();
251
		if(is_array($self->supported_list))
252
		{
253
			foreach($self->supported_list AS $key => $value)
254
			{
255
				if(!$value->enable)
256
				{
257
					$disableList[] = $value;
258
				}
259
			}
260
		}
261
		return $disableList;
262
	}
263
264
	/**
265
	 * returns list of supported dbms list
266
	 * this method is private
267
	 * @return array return supported DBMS list
268
	 */
269
	function _getSupportedList()
270
	{
271
		static $get_supported_list = '';
272
		if(is_array($get_supported_list))
273
		{
274
			$this->supported_list = $get_supported_list;
275
			return $this->supported_list;
276
		}
277
		$get_supported_list = array();
278
		$db_classes_path = _XE_PATH_ . "classes/db/";
279
		$filter = "/^DB([^\.]+)\.class\.php/i";
280
		$supported_list = FileHandler::readDir($db_classes_path, $filter, TRUE);
281
282
		// after creating instance of class, check is supported
283
		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...
284
		{
285
			$db_type = $supported_list[$i];
286
287
			$class_name = sprintf("DB%s%s", strtoupper(substr($db_type, 0, 1)), strtolower(substr($db_type, 1)));
288
			$class_file = sprintf(_XE_PATH_ . "classes/db/%s.class.php", $class_name);
289
			if(!file_exists($class_file))
290
			{
291
				continue;
292
			}
293
294
			unset($oDB);
295
			require_once($class_file);
296
			$oDB = new $class_name();
297
298
			if(!$oDB)
299
			{
300
				continue;
301
			}
302
303
			$obj = new stdClass;
304
			$obj->db_type = $db_type;
305
			$obj->enable = $oDB->isSupported() ? TRUE : FALSE;
306
307
			$get_supported_list[] = $obj;
308
		}
309
310
		// sort
311
		@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...
312
313
		$this->supported_list = $get_supported_list;
314
		return $this->supported_list;
315
	}
316
317
	/**
318
	 * sort dbms as priority
319
	 */
320
	function _sortDBMS($a, $b)
321
	{
322
		if(!isset($this->priority_dbms[$a->db_type]))
323
		{
324
			$priority_a = 0;
325
		}
326
		else
327
		{
328
			$priority_a = $this->priority_dbms[$a->db_type];
329
		}
330
331
		if(!isset($this->priority_dbms[$b->db_type]))
332
		{
333
			$priority_b = 0;
334
		}
335
		else
336
		{
337
			$priority_b = $this->priority_dbms[$b->db_type];
338
		}
339
340
		if($priority_a == $priority_b)
341
		{
342
			return 0;
343
		}
344
345
		return ($priority_a > $priority_b) ? -1 : 1;
346
	}
347
348
	/**
349
	 * Return dbms supportable status
350
	 * The value is set in the child class
351
	 * @return boolean true: is supported, false: is not supported
352
	 */
353
	function isSupported()
354
	{
355
		return self::$isSupported;
356
	}
357
358
	/**
359
	 * Return connected status
360
	 * @param string $type master or slave
361
	 * @param int $indx key of server list
362
	 * @return boolean true: connected, false: not connected
363
	 */
364
	function isConnected($type = 'master', $indx = 0)
365
	{
366
		if($type == 'master')
367
		{
368
			return $this->master_db["is_connected"] ? TRUE : FALSE;
369
		}
370
		else
371
		{
372
			return $this->slave_db[$indx]["is_connected"] ? TRUE : FALSE;
373
		}
374
	}
375
376
	/**
377
	 * start recording log
378
	 * @param string $query query string
379
	 * @return void
380
	 */
381
	function actStart($query)
382
	{
383
		$this->setError(0, 'success');
384
		$this->query = $query;
385
		$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...
386
		$this->elapsed_time = 0;
387
	}
388
389
	/**
390
	 * finish recording log
391
	 * @return void
392
	 */
393
	function actFinish()
394
	{
395
		if(!$this->query)
396
		{
397
			return;
398
		}
399
		$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...
400
		$elapsed_time = $this->act_finish - $this->act_start;
401
		$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...
402
		$GLOBALS['__db_elapsed_time__'] += $elapsed_time;
403
404
		$site_module_info = Context::get('site_module_info');
405
		$log = array();
406
		$log['query'] = $this->query;
407
		$log['elapsed_time'] = $elapsed_time;
408
		$log['connection'] = $this->connection;
409
		$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...
410
		$log['module'] = $site_module_info->module;
411
		$log['act'] = Context::get('act');
412
		$log['time'] = date('Y-m-d H:i:s');
413
414
		$bt = version_compare(PHP_VERSION, '5.3.6', '>=') ? debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS) : debug_backtrace();
415
416
		foreach($bt as $no => $call)
417
		{
418
			if($call['function'] == 'executeQuery' || $call['function'] == 'executeQueryArray')
419
			{
420
				$call_no = $no;
421
				$call_no++;
422
				$log['called_file'] = $bt[$call_no]['file'].':'.$bt[$call_no]['line'];
423
				$log['called_file'] = str_replace(_XE_PATH_ , '', $log['called_file']);
424
				$call_no++;
425
				$log['called_method'] = $bt[$call_no]['class'].$bt[$call_no]['type'].$bt[$call_no]['function'];
426
				break;
427
			}
428
		}
429
430
		// leave error log if an error occured (if __DEBUG_DB_OUTPUT__ is defined)
431
		if($this->isError())
432
		{
433
			$log['result'] = 'Failed';
434
			$log['errno'] = $this->errno;
435
			$log['errstr'] = $this->errstr;
436
437
			if(__DEBUG_DB_OUTPUT__ == 1)
438
			{
439
				$debug_file = _XE_PATH_ . "files/_debug_db_query.php";
440
				$buff = array();
441
				if(!file_exists($debug_file))
442
				{
443
					$buff[] = '<?php exit(); ?' . '>';
444
				}
445
				$buff[] = print_r($log, TRUE);
446
				@file_put_contents($log_file, implode("\n", $buff) . "\n\n", FILE_APPEND|LOCK_EX);
0 ignored issues
show
Bug introduced by
The variable $log_file does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
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...
447
			}
448
		}
449
		else
450
		{
451
			$log['result'] = 'Success';
452
		}
453
454
		$this->setQueryLog($log);
455
456
		$log_args = new stdClass;
457
		$log_args->query = $this->query;
458
		$log_args->query_id = $this->query_id;
459
		$log_args->caller = $log['called_method'] . '() in ' . $log['called_file'];
460
		$log_args->connection = $log['connection'];
461
		writeSlowlog('query', $elapsed_time, $log_args);
462
	}
463
464
	/**
465
	 * set query debug log
466
	 * @param array $log values set query debug
467
	 * @return void
468
	*/
469
	function setQueryLog($log)
470
	{
471
		$GLOBALS['__db_queries__'][] = $log;
472
	}
473
474
	/**
475
	 * set error
476
	 * @param int $errno error code
477
	 * @param string $errstr error message
478
	 * @return void
479
	 */
480
	function setError($errno = 0, $errstr = 'success')
481
	{
482
		$this->errno = $errno;
483
		$this->errstr = $errstr;
484
	}
485
486
	/**
487
	 * Return error status
488
	 * @return boolean true: error, false: no error
489
	 */
490
	function isError()
491
	{
492
		return ($this->errno !== 0);
493
	}
494
495
	/**
496
	 * Returns object of error info
497
	 * @return object object of error
498
	 */
499
	function getError()
500
	{
501
		$this->errstr = Context::convertEncodingStr($this->errstr);
502
		return new Object($this->errno, $this->errstr);
503
	}
504
505
	/**
506
	 * Execute Query that result of the query xml file
507
	 * This function finds xml file or cache file of $query_id, compiles it and then execute it
508
	 * @param string $query_id query id (module.queryname)
509
	 * @param array|object $args arguments for query
510
	 * @param array $arg_columns column list. if you want get specific colums from executed result, add column list to $arg_columns
511
	 * @return object result of query
512
	 */
513
	function executeQuery($query_id, $args = NULL, $arg_columns = NULL, $type = NULL)
514
	{
515
		static $cache_file = array();
516
517
		if(!$query_id)
518
		{
519
			return new Object(-1, 'msg_invalid_queryid');
520
		}
521
		if(!$this->db_type)
522
		{
523
			return;
524
		}
525
526
		$this->actDBClassStart();
527
528
		$this->query_id = $query_id;
529
530
		if(!isset($cache_file[$query_id]) || !file_exists($cache_file[$query_id]))
531
		{
532
			$id_args = explode('.', $query_id);
533
			if(count($id_args) == 2)
534
			{
535
				$target = 'modules';
536
				$module = $id_args[0];
537
				$id = $id_args[1];
538
			}
539 View Code Duplication
			elseif(count($id_args) == 3)
540
			{
541
				$target = $id_args[0];
542
				$typeList = array('addons' => 1, 'widgets' => 1);
543
				if(!isset($typeList[$target]))
544
				{
545
					$this->actDBClassFinish();
546
					return;
547
				}
548
				$module = $id_args[1];
549
				$id = $id_args[2];
550
			}
551
			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...
552
			{
553
				$this->actDBClassFinish();
554
				return new Object(-1, 'msg_invalid_queryid');
555
			}
556
557
			$xml_file = sprintf('%s%s/%s/queries/%s.xml', _XE_PATH_, $target, $module, $id);
558
			if(!file_exists($xml_file))
559
			{
560
				$this->actDBClassFinish();
561
				return new Object(-1, 'msg_invalid_queryid');
562
			}
563
564
			// look for cache file
565
			$cache_file[$query_id] = $this->checkQueryCacheFile($query_id, $xml_file);
566
		}
567
		$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 513 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 513 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...
568
569
		$this->actDBClassFinish();
570
		// execute query
571
		return $result;
572
	}
573
574
	/**
575
	 * Look for query cache file
576
	 * @param string $query_id query id for finding
577
	 * @param string $xml_file original xml query file
578
	 * @return string cache file
579
	 */
580
	function checkQueryCacheFile($query_id, $xml_file)
581
	{
582
		// first try finding cache file
583
		$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...
584
585
		$cache_time = -1;
586
		if(file_exists($cache_file))
587
		{
588
			$cache_time = filemtime($cache_file);
589
		}
590
591
		// if there is no cache file or is not new, find original xml query file and parse it
592
		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'))
593
		{
594
			$oParser = new XmlQueryParser();
595
			$oParser->parse($query_id, $xml_file, $cache_file);
596
		}
597
598
		return $cache_file;
599
	}
600
601
	/**
602
	 * Execute query and return the result
603
	 * @param string $cache_file cache file of query
604
	 * @param array|object $source_args arguments for query
605
	 * @param string $query_id query id
606
	 * @param array $arg_columns column list. if you want get specific colums from executed result, add column list to $arg_columns
607
	 * @return object result of query
608
	 */
609
	function _executeQuery($cache_file, $source_args, $query_id, $arg_columns, $type)
610
	{
611
		global $lang;
612
		
613
		if(!in_array($type, array('master','slave'))) $type = 'slave';
614
615
		if(!file_exists($cache_file))
616
		{
617
			return new Object(-1, 'msg_invalid_queryid');
618
		}
619
620
		if($source_args)
621
		{
622
			$args = clone $source_args;
623
		}
624
625
		$output = include($cache_file);
626
627 View Code Duplication
		if((is_a($output, 'Object') || is_subclass_of($output, 'Object')) && !$output->toBool())
628
		{
629
			return $output;
630
		}
631
632
		// execute appropriate query
633
		switch($output->getAction())
634
		{
635
			case 'insert' :
636
			case 'insert-select' :
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->_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...
639
				break;
640
			case 'update' :
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->_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...
643
				break;
644
			case 'delete' :
645
				$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...
646
				$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...
647
				break;
648
			case 'select' :
649
				$arg_columns = is_array($arg_columns) ? $arg_columns : array();
650
				$output->setColumnList($arg_columns);
651
				$connection = $this->_getConnection($type);
652
				$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...
653
				break;
654
		}
655
656
		if($this->isError())
657
		{
658
			$output = $this->getError();
659
		}
660 View Code Duplication
		else if(!is_a($output, 'Object') && !is_subclass_of($output, 'Object'))
661
		{
662
			$output = new Object();
663
		}
664
		$output->add('_query', $this->query);
665
		$output->add('_elapsed_time', sprintf("%0.5f", $this->elapsed_time));
666
667
		return $output;
668
	}
669
670
	/**
671
	 * Returns counter cache data
672
	 * @param array|string $tables tables to get data
673
	 * @param string $condition condition to get data
674
	 * @return int count of cache data
675
	 */
676
	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...
677
	{
678
		return FALSE;
679
/*
680
		if(!$tables)
681
		{
682
			return FALSE;
683
		}
684
		if(!is_dir($this->count_cache_path))
685
		{
686
			return FileHandler::makeDir($this->count_cache_path);
687
		}
688
689
		$condition = md5($condition);
690
691
		if(!is_array($tables))
692
		{
693
			$tables_str = $tables;
694
		}
695
		else
696
		{
697
			$tables_str = implode('.', $tables);
698
		}
699
700
		$cache_path = sprintf('%s/%s%s', $this->count_cache_path, $this->prefix, $tables_str);
701
		FileHandler::makeDir($cache_path);
702
703
		$cache_filename = sprintf('%s/%s.%s', $cache_path, $tables_str, $condition);
704
		if(!file_exists($cache_filename))
705
		{
706
			return FALSE;
707
		}
708
709
		$cache_mtime = filemtime($cache_filename);
710
711
		if(!is_array($tables))
712
		{
713
			$tables = array($tables);
714
		}
715
		foreach($tables as $alias => $table)
716
		{
717
			$table_filename = sprintf('%s/cache.%s%s', $this->count_cache_path, $this->prefix, $table);
718
			if(!file_exists($table_filename) || filemtime($table_filename) > $cache_mtime)
719
			{
720
				return FALSE;
721
			}
722
		}
723
724
		$count = (int) FileHandler::readFile($cache_filename);
725
		return $count;
726
*/
727
	}
728
729
	/**
730
	 * Save counter cache data
731
	 * @param array|string $tables tables to save data
732
	 * @param string $condition condition to save data
733
	 * @param int $count count of cache data to save
734
	 * @return void
735
	 */
736
	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...
737
	{
738
		return FALSE;
739
/*
740
		if(!$tables)
741
		{
742
			return FALSE;
743
		}
744
		if(!is_dir($this->count_cache_path))
745
		{
746
			return FileHandler::makeDir($this->count_cache_path);
747
		}
748
749
		$condition = md5($condition);
750
751
		if(!is_array($tables))
752
		{
753
			$tables_str = $tables;
754
		}
755
		else
756
		{
757
			$tables_str = implode('.', $tables);
758
		}
759
760
		$cache_path = sprintf('%s/%s%s', $this->count_cache_path, $this->prefix, $tables_str);
761
		FileHandler::makeDir($cache_path);
762
763
		$cache_filename = sprintf('%s/%s.%s', $cache_path, $tables_str, $condition);
764
765
		FileHandler::writeFile($cache_filename, $count);
766
*/
767
	}
768
769
	/**
770
	 * Reset counter cache data
771
	 * @param array|string $tables tables to reset cache data
772
	 * @return boolean true: success, false: failed
773
	 */
774
	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...
775
	{
776
		return FALSE;
777
/*
778
		if(!$tables)
779
		{
780
			return FALSE;
781
		}
782
		return FileHandler::makeDir($this->count_cache_path);
783
784
		if(!is_array($tables))
785
		{
786
			$tables = array($tables);
787
		}
788
		foreach($tables as $alias => $table)
789
		{
790
			$filename = sprintf('%s/cache.%s%s', $this->count_cache_path, $this->prefix, $table);
791
			FileHandler::removeFile($filename);
792
			FileHandler::writeFile($filename, '');
793
		}
794
795
		return TRUE;
796
 */
797
	}
798
799
	/**
800
	 * Drop tables
801
	 * @param string $table_name
802
	 * @return void
803
	 */
804
	function dropTable($table_name)
805
	{
806
		if(!$table_name)
807
		{
808
			return;
809
		}
810
		$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...
811
		$this->_query($query);
812
	}
813
814
	/**
815
	 * Return select query string
816
	 * @param object $query
817
	 * @param boolean $with_values
818
	 * @return string
819
	 */
820
	function getSelectSql($query, $with_values = TRUE)
821
	{
822
		$select = $query->getSelectString($with_values);
823
		if($select == '')
824
		{
825
			return new Object(-1, "Invalid query");
826
		}
827
		$select = 'SELECT ' . $select;
828
829
		$from = $query->getFromString($with_values);
830
		if($from == '')
831
		{
832
			return new Object(-1, "Invalid query");
833
		}
834
		$from = ' FROM ' . $from;
835
836
		$where = $query->getWhereString($with_values);
837
		if($where != '')
838
		{
839
			$where = ' WHERE ' . $where;
840
		}
841
842
		$tableObjects = $query->getTables();
843
		$index_hint_list = '';
844
		foreach($tableObjects as $tableObject)
845
		{
846
			if(is_a($tableObject, 'CubridTableWithHint'))
847
			{
848
				$index_hint_list .= $tableObject->getIndexHintString() . ', ';
849
			}
850
		}
851
		$index_hint_list = substr($index_hint_list, 0, -2);
852
		if($index_hint_list != '')
853
		{
854
			$index_hint_list = 'USING INDEX ' . $index_hint_list;
855
		}
856
857
		$groupBy = $query->getGroupByString();
858
		if($groupBy != '')
859
		{
860
			$groupBy = ' GROUP BY ' . $groupBy;
861
		}
862
863
		$orderBy = $query->getOrderByString();
864
		if($orderBy != '')
865
		{
866
			$orderBy = ' ORDER BY ' . $orderBy;
867
		}
868
869
		$limit = $query->getLimitString();
870
		if($limit != '')
871
		{
872
			$limit = ' LIMIT ' . $limit;
873
		}
874
875
		return $select . ' ' . $from . ' ' . $where . ' ' . $index_hint_list . ' ' . $groupBy . ' ' . $orderBy . ' ' . $limit;
876
	}
877
878
	/**
879
	 * Given a SELECT statement that uses click count
880
	 * returns the corresponding update sql string
881
	 * for databases that don't have click count support built in
882
	 * (aka all besides CUBRID)
883
	 *
884
	 * Function does not check if click count columns exist!
885
	 * You must call $query->usesClickCount() before using this function
886
	 *
887
	 * @param $queryObject
888
	 */
889
	function getClickCountQuery($queryObject)
890
	{
891
		$new_update_columns = array();
892
		$click_count_columns = $queryObject->getClickCountColumns();
893
		foreach($click_count_columns as $click_count_column)
894
		{
895
			$click_count_column_name = $click_count_column->column_name;
896
897
			$increase_by_1 = new Argument($click_count_column_name, null);
898
			$increase_by_1->setColumnOperation('+');
899
			$increase_by_1->ensureDefaultValue(1);
900
901
			$update_expression = new UpdateExpression($click_count_column_name, $increase_by_1);
902
			$new_update_columns[] = $update_expression;
903
		}
904
		$queryObject->columns = $new_update_columns;
905
		return $queryObject;
906
	}
907
908
	/**
909
	 * Return delete query string
910
	 * @param object $query
911
	 * @param boolean $with_values
912
	 * @param boolean $with_priority
913
	 * @return string
914
	 */
915
	function getDeleteSql($query, $with_values = TRUE, $with_priority = FALSE)
916
	{
917
		$sql = 'DELETE ';
918
919
		$sql .= $with_priority ? $query->getPriority() : '';
920
		$tables = $query->getTables();
921
922
		$sql .= $tables[0]->getAlias();
923
924
		$from = $query->getFromString($with_values);
925
		if($from == '')
926
		{
927
			return new Object(-1, "Invalid query");
928
		}
929
		$sql .= ' FROM ' . $from;
930
931
		$where = $query->getWhereString($with_values);
932
		if($where != '')
933
		{
934
			$sql .= ' WHERE ' . $where;
935
		}
936
937
		return $sql;
938
	}
939
940
	/**
941
	 * Return update query string
942
	 * @param object $query
943
	 * @param boolean $with_values
944
	 * @param boolean $with_priority
945
	 * @return string
946
	 */
947
	function getUpdateSql($query, $with_values = TRUE, $with_priority = FALSE)
948
	{
949
		$columnsList = $query->getUpdateString($with_values);
950
		if($columnsList == '')
951
		{
952
			return new Object(-1, "Invalid query");
953
		}
954
955
		$tables = $query->getFromString($with_values);
956
		if($tables == '')
957
		{
958
			return new Object(-1, "Invalid query");
959
		}
960
961
		$where = $query->getWhereString($with_values);
962
		if($where != '')
963
		{
964
			$where = ' WHERE ' . $where;
965
		}
966
967
		$priority = $with_priority ? $query->getPriority() : '';
968
969
		return "UPDATE $priority $tables SET $columnsList " . $where;
970
	}
971
972
	/**
973
	 * Return insert query string
974
	 * @param object $query
975
	 * @param boolean $with_values
976
	 * @param boolean $with_priority
977
	 * @return string
978
	 */
979
	function getInsertSql($query, $with_values = TRUE, $with_priority = FALSE)
980
	{
981
		$tableName = $query->getFirstTableName();
982
		$values = $query->getInsertString($with_values);
983
		$priority = $with_priority ? $query->getPriority() : '';
984
985
		return "INSERT $priority INTO $tableName \n $values";
986
	}
987
988
	/**
989
	 * Return index from slave server list
990
	 * @return int
991
	 */
992
	function _getSlaveConnectionStringIndex()
993
	{
994
		$max = count($this->slave_db);
995
		$indx = rand(0, $max - 1);
996
		return $indx;
997
	}
998
999
	/**
1000
	 * Return connection resource
1001
	 * @param string $type use 'master' or 'slave'. default value is 'master'
1002
	 * @param int $indx if indx value is NULL, return rand number in slave server list
1003
	 * @return resource
1004
	 */
1005
	function _getConnection($type = 'master', $indx = NULL)
1006
	{
1007
		if($type == 'master')
1008
		{
1009
			if(!$this->master_db['is_connected'])
1010
			{
1011
				$this->_connect($type);
1012
			}
1013
			$this->connection = 'Master ' . $this->master_db['db_hostname'];
1014
			return $this->master_db["resource"];
1015
		}
1016
1017
		if($indx === NULL)
1018
		{
1019
			$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...
1020
		}
1021
1022
		if(!$this->slave_db[$indx]['is_connected'])
1023
		{
1024
			$this->_connect($type, $indx);
1025
		}
1026
1027
		$this->connection = 'Slave ' . $this->slave_db[$indx]['db_hostname'];
1028
		return $this->slave_db[$indx]["resource"];
1029
	}
1030
1031
	/**
1032
	 * check db information exists
1033
	 * @return boolean
1034
	 */
1035
	function _dbInfoExists()
1036
	{
1037
		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...
1038
		{
1039
			return FALSE;
1040
		}
1041
		if(count($this->slave_db) === 0)
1042
		{
1043
			return FALSE;
1044
		}
1045
		return TRUE;
1046
	}
1047
1048
	/**
1049
	 * DB disconnection
1050
	 * this method is protected
1051
	 * @param resource $connection
1052
	 * @return void
1053
	 */
1054
	function _close($connection)
1055
	{
1056
1057
	}
1058
1059
	/**
1060
	 * DB disconnection
1061
	 * @param string $type 'master' or 'slave'
1062
	 * @param int $indx number in slave dbms server list
1063
	 * @return void
1064
	 */
1065
	function close($type = 'master', $indx = 0)
1066
	{
1067
		if(!$this->isConnected($type, $indx))
1068
		{
1069
			return;
1070
		}
1071
1072
		if($type == 'master')
1073
		{
1074
			$connection = &$this->master_db;
1075
		}
1076
		else
1077
		{
1078
			$connection = &$this->slave_db[$indx];
1079
		}
1080
1081
		$this->commit();
1082
		$this->_close($connection["resource"]);
1083
1084
		$connection["is_connected"] = FALSE;
1085
	}
1086
1087
	/**
1088
	 * DB transaction start
1089
	 * this method is protected
1090
	 * @return boolean
1091
	 */
1092
	function _begin($transactionLevel = 0)
1093
	{
1094
		return TRUE;
1095
	}
1096
1097
	/**
1098
	 * DB transaction start
1099
	 * @return void
1100
	 */
1101
	function begin()
1102
	{
1103
		if(!$this->isConnected())
1104
		{
1105
			return;
1106
		}
1107
1108
		if($this->_begin($this->transactionNestedLevel))
1109
		{
1110
			$this->transaction_started = TRUE;
1111
			$this->transactionNestedLevel++;
1112
		}
1113
	}
1114
1115
	/**
1116
	 * DB transaction rollback
1117
	 * this method is protected
1118
	 * @return boolean
1119
	 */
1120
	function _rollback($transactionLevel = 0)
1121
	{
1122
		return TRUE;
1123
	}
1124
1125
	/**
1126
	 * DB transaction rollback
1127
	 * @return void
1128
	 */
1129
	function rollback()
1130
	{
1131
		if(!$this->isConnected() || !$this->transaction_started)
1132
		{
1133
			return;
1134
		}
1135
		if($this->_rollback($this->transactionNestedLevel))
1136
		{
1137
			$this->transactionNestedLevel--;
1138
1139
			if(!$this->transactionNestedLevel)
1140
			{
1141
				$this->transaction_started = FALSE;
1142
			}
1143
		}
1144
	}
1145
1146
	/**
1147
	 * DB transaction commit
1148
	 * this method is protected
1149
	 * @return boolean
1150
	 */
1151
	function _commit()
1152
	{
1153
		return TRUE;
1154
	}
1155
1156
	/**
1157
	 * DB transaction commit
1158
	 * @param boolean $force regardless transaction start status or connect status, forced to commit
1159
	 * @return void
1160
	 */
1161
	function commit($force = FALSE)
1162
	{
1163
		if(!$force && (!$this->isConnected() || !$this->transaction_started))
1164
		{
1165
			return;
1166
		}
1167
		if($this->transactionNestedLevel == 1 && $this->_commit())
1168
		{
1169
			$this->transaction_started = FALSE;
1170
			$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...
1171
		}
1172
		else
1173
		{
1174
			$this->transactionNestedLevel--;
1175
		}
1176
	}
1177
1178
	/**
1179
	 * Execute the query
1180
	 * this method is protected
1181
	 * @param string $query
1182
	 * @param resource $connection
1183
	 * @return void
1184
	 */
1185
	function __query($query, $connection)
1186
	{
1187
1188
	}
1189
1190
	/**
1191
	 * Execute the query
1192
	 * this method is protected
1193
	 * @param string $query
1194
	 * @param resource $connection
1195
	 * @return resource
1196
	 */
1197
	function _query($query, $connection = NULL)
1198
	{
1199
		if($connection == NULL)
1200
		{
1201
			$connection = $this->_getConnection('master');
1202
		}
1203
		// Notify to start a query execution
1204
		$this->actStart($query);
1205
1206
		// Run the query statement
1207
		$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...
1208
1209
		// Notify to complete a query execution
1210
		$this->actFinish();
1211
		// Return result
1212
		return $result;
1213
	}
1214
1215
	/**
1216
	 * DB info settings
1217
	 * this method is protected
1218
	 * @return void
1219
	 */
1220
	function _setDBInfo()
1221
	{
1222
		$db_info = Context::getDBInfo();
1223
		$this->master_db = $db_info->master_db;
1224
		if($db_info->master_db["db_hostname"] == $db_info->slave_db[0]["db_hostname"]
1225
				&& $db_info->master_db["db_port"] == $db_info->slave_db[0]["db_port"]
1226
				&& $db_info->master_db["db_userid"] == $db_info->slave_db[0]["db_userid"]
1227
				&& $db_info->master_db["db_password"] == $db_info->slave_db[0]["db_password"]
1228
				&& $db_info->master_db["db_database"] == $db_info->slave_db[0]["db_database"]
1229
		)
1230
		{
1231
			$this->slave_db[0] = &$this->master_db;
1232
		}
1233
		else
1234
		{
1235
			$this->slave_db = $db_info->slave_db;
1236
		}
1237
		$this->prefix = $db_info->master_db["db_table_prefix"];
1238
		$this->use_prepared_statements = $db_info->use_prepared_statements;
1239
	}
1240
1241
	/**
1242
	 * DB Connect
1243
	 * this method is protected
1244
	 * @param array $connection
1245
	 * @return void
1246
	 */
1247
	function __connect($connection)
1248
	{
1249
1250
	}
1251
1252
	/**
1253
	 * If have a task after connection, add a taks in this method
1254
	 * this method is protected
1255
	 * @param resource $connection
1256
	 * @return void
1257
	 */
1258
	function _afterConnect($connection)
1259
	{
1260
1261
	}
1262
1263
	/**
1264
	 * DB Connect
1265
	 * this method is protected
1266
	 * @param string $type 'master' or 'slave'
1267
	 * @param int $indx number in slave dbms server list
1268
	 * @return void
1269
	 */
1270
	function _connect($type = 'master', $indx = 0)
1271
	{
1272
		if($this->isConnected($type, $indx))
1273
		{
1274
			return;
1275
		}
1276
1277
		// Ignore if no DB information exists
1278
		if(!$this->_dbInfoExists())
1279
		{
1280
			return;
1281
		}
1282
1283
		if($type == 'master')
1284
		{
1285
			$connection = &$this->master_db;
1286
		}
1287
		else
1288
		{
1289
			$connection = &$this->slave_db[$indx];
1290
		}
1291
1292
		$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...
1293
		if($result === NULL || $result === FALSE)
1294
		{
1295
			$connection["is_connected"] = FALSE;
1296
			return;
1297
		}
1298
1299
		// Check connections
1300
		$connection["resource"] = $result;
1301
		$connection["is_connected"] = TRUE;
1302
1303
		// Save connection info for db logs
1304
		$this->connection = ucfirst($type) . ' ' . $connection["db_hostname"];
1305
1306
		// regist $this->close callback
1307
		register_shutdown_function(array($this, "close"));
1308
1309
		$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...
1310
	}
1311
1312
	/**
1313
	 * Start recording DBClass log
1314
	 * @return void
1315
	 */
1316
	function actDBClassStart()
1317
	{
1318
		$this->setError(0, 'success');
1319
		$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...
1320
		$this->elapsed_dbclass_time = 0;
1321
	}
1322
1323
	/**
1324
	 * Finish recording DBClass log
1325
	 * @return void
1326
	 */
1327
	function actDBClassFinish()
1328
	{
1329
		if(!$this->query)
1330
		{
1331
			return;
1332
		}
1333
		$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...
1334
		$elapsed_dbclass_time = $this->act_dbclass_finish - $this->act_dbclass_start;
1335
		$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...
1336
		$GLOBALS['__dbclass_elapsed_time__'] += $elapsed_dbclass_time;
1337
	}
1338
1339
	/**
1340
	 * Returns a database specific parser instance
1341
	 * used for escaping expressions and table/column identifiers
1342
	 *
1343
	 * Requires an implementation of the DB class (won't work if database is not set)
1344
	 * this method is singleton
1345
	 *
1346
	 * @param boolean $force force load DBParser instance
1347
	 * @return DBParser
1348
	 */
1349
	function &getParser($force = FALSE)
1350
	{
1351
		static $dbParser = NULL;
1352
		if(!$dbParser || $force)
1353
		{
1354
			$oDB = DB::getInstance();
1355
			$dbParser = $oDB->getParser();
1356
		}
1357
1358
		return $dbParser;
1359
	}
1360
1361
}
1362
/* End of file DB.class.php */
1363
/* Location: ./classes/db/DB.class.php */
1364