Completed
Push — release-2.1 ( e6c696...22bfba )
by Mathias
07:04
created

Subs-Db-mysqli.php ➔ smf_db_select()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 1
nop 2
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file has all the main functions in it that relate to the database.
5
 *
6
 * Simple Machines Forum (SMF)
7
 *
8
 * @package SMF
9
 * @author Simple Machines http://www.simplemachines.org
10
 * @copyright 2012 Simple Machines
11
 * @license http://www.simplemachines.org/about/smf/license.php BSD
12
 *
13
 * @version 2.1 Beta 3
14
 */
15
16
if (!defined('SMF'))
17
	die('No direct access...');
18
19
/**
20
 *  Maps the implementations in this file (smf_db_function_name)
21
 *  to the $smcFunc['db_function_name'] variable.
22
 *
23
 * @param string $db_server The database server
24
 * @param string $db_name The name of the database
25
 * @param string $db_user The database username
26
 * @param string $db_passwd The database password
27
 * @param string $db_prefix The table prefix
28
 * @param array $db_options An array of database options
29
 * @return null|resource Returns null on failure if $db_options['non_fatal'] is true or a MySQL connection resource handle if the connection was successful.
30
 */
31
function smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $db_options = array())
0 ignored issues
show
Best Practice introduced by
The function smf_db_initiate() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L31-93) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
Unused Code introduced by
The parameter $db_prefix 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...
32
{
33
	global $smcFunc, $mysql_set_mode;
34
35
	// Map some database specific functions, only do this once.
36 View Code Duplication
	if (!isset($smcFunc['db_fetch_assoc']) || $smcFunc['db_fetch_assoc'] != 'mysqli_fetch_assoc')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
37
		$smcFunc += array(
38
			'db_query'                  => 'smf_db_query',
39
			'db_quote'                  => 'smf_db_quote',
40
			'db_fetch_assoc'            => 'mysqli_fetch_assoc',
41
			'db_fetch_row'              => 'mysqli_fetch_row',
42
			'db_free_result'            => 'mysqli_free_result',
43
			'db_insert'                 => 'smf_db_insert',
44
			'db_insert_id'              => 'smf_db_insert_id',
45
			'db_num_rows'               => 'mysqli_num_rows',
46
			'db_data_seek'              => 'mysqli_data_seek',
47
			'db_num_fields'             => 'mysqli_num_fields',
48
			'db_escape_string'          => 'addslashes',
49
			'db_unescape_string'        => 'stripslashes',
50
			'db_server_info'            => 'smf_db_get_server_info',
51
			'db_affected_rows'          => 'smf_db_affected_rows',
52
			'db_transaction'            => 'smf_db_transaction',
53
			'db_error'                  => 'mysqli_error',
54
			'db_select_db'              => 'smf_db_select',
55
			'db_title'                  => 'MySQLi',
56
			'db_sybase'                 => false,
57
			'db_case_sensitive'         => false,
58
			'db_escape_wildcard_string' => 'smf_db_escape_wildcard_string',
59
			'db_is_resource'            => 'smf_is_resource',
60
		);
61
62
	if (!empty($db_options['persist']))
63
		$db_server = 'p:' . $db_server;
64
65
	$connection = mysqli_init();
66
	
67
	$flags = MYSQLI_CLIENT_FOUND_ROWS;
68
	
69
	$success = false;
70
	
71
	if ($connection) {
72
		if (!empty($db_options['port']))
73
			$success = mysqli_real_connect($connection, $db_server, $db_user, $db_passwd, '', $db_options['port'] , null ,$flags);
74
		else
75
			$success = mysqli_real_connect($connection, $db_server, $db_user, $db_passwd,'', 0, null, $flags);
76
	}
77
78
	// Something's wrong, show an error if its fatal (which we assume it is)
79
	if ($success === false)
80
	{
81
		if (!empty($db_options['non_fatal']))
82
			return null;
83
		else
84
			display_db_error();
85
	}
86
87
	// Select the database, unless told not to
88 View Code Duplication
	if (empty($db_options['dont_select_db']) && !@mysqli_select_db($connection, $db_name) && empty($db_options['non_fatal']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
89
		display_db_error();
90
91
	// This makes it possible to have SMF automatically change the sql_mode and autocommit if needed.
92 View Code Duplication
	if (isset($mysql_set_mode) && $mysql_set_mode === true)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
93
		$smcFunc['db_query']('', 'SET sql_mode = \'\', AUTOCOMMIT = 1',
94
		array(),
95
		false
96
	);
97
98
	return $connection;
99
}
100
101
/**
102
 * Extend the database functionality. It calls the respective file's init
103
 * to add the implementations in that file to $smcFunc array.
104
 *
105
 * @param string $type Indicates which additional file to load. ('extra', 'packages')
106
 */
107
function db_extend($type = 'extra')
0 ignored issues
show
Best Practice introduced by
The function db_extend() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L101-108) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
108
{
109
	global $sourcedir;
110
111
	// we force the MySQL files as nothing syntactically changes with MySQLi
112
	require_once($sourcedir . '/Db' . strtoupper($type[0]) . substr($type, 1) . '-mysql.php');
113
	$initFunc = 'db_' . $type . '_init';
114
	$initFunc();
115
}
116
117
/**
118
 * Fix up the prefix so it doesn't require the database to be selected.
119
 *
120
 * @param string &$db_prefix The table prefix
121
 * @param string $db_name The database name
122
 */
123
function db_fix_prefix(&$db_prefix, $db_name)
0 ignored issues
show
Best Practice introduced by
The function db_fix_prefix() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L116-119) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
124
{
125
	$db_prefix = is_numeric(substr($db_prefix, 0, 1)) ? $db_name . '.' . $db_prefix : '`' . $db_name . '`.' . $db_prefix;
126
}
127
128
/**
129
 * Wrap mysqli_select_db so the connection does not need to be specified
130
 *
131
 * @param string &$database The database
132
 * @param object $connection The connection object (if null, $db_connection is used)
133
 * @return bool Whether the database was selected
134
 */
135
function smf_db_select($database, $connection = null)
136
{
137
	global $db_connection;
138
	return mysqli_select_db($connection === null ? $db_connection : $connection, $database);
139
}
140
141
/**
142
 * Wrap mysqli_get_server_info so the connection does not need to be specified
143
 *
144
 * @param object $connection The connection to use (if null, $db_connection is used)
145
 * @return string The server info
146
 */
147
function smf_db_get_server_info($connection = null)
148
{
149
	global $db_connection;
150
	return mysqli_get_server_info($connection === null ? $db_connection : $connection);
151
}
152
153
/**
154
 * Callback for preg_replace_callback on the query.
155
 * It allows to replace on the fly a few pre-defined strings, for convenience ('query_see_board', 'query_wanna_see_board'), with
156
 * their current values from $user_info.
157
 * In addition, it performs checks and sanitization on the values sent to the database.
158
 *
159
 * @param array $matches The matches from preg_replace_callback
160
 * @return string The appropriate string depending on $matches[1]
161
 */
162 View Code Duplication
function smf_db_replacement__callback($matches)
0 ignored issues
show
Duplication introduced by
This function 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...
Best Practice introduced by
The function smf_db_replacement__callback() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L130-274) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
163
{
164
	global $db_callback, $user_info, $db_prefix, $smcFunc;
165
166
	list ($values, $connection) = $db_callback;
167
	if (!is_object($connection))
168
		display_db_error();
169
170
	if ($matches[1] === 'db_prefix')
171
		return $db_prefix;
172
173
	if ($matches[1] === 'query_see_board')
174
		return $user_info['query_see_board'];
175
176
	if ($matches[1] === 'query_wanna_see_board')
177
		return $user_info['query_wanna_see_board'];
178
179
	if ($matches[1] === 'empty')
180
		return '\'\'';
181
182
	if (!isset($matches[2]))
183
		smf_db_error_backtrace('Invalid value inserted or no type specified.', '', E_USER_ERROR, __FILE__, __LINE__);
184
185
	if ($matches[1] === 'literal')
186
		return '\'' . mysqli_real_escape_string($connection, $matches[2]) . '\'';
187
188
	if (!isset($values[$matches[2]]))
189
		smf_db_error_backtrace('The database value you\'re trying to insert does not exist: ' . (isset($smcFunc['htmlspecialchars']) ? $smcFunc['htmlspecialchars']($matches[2]) : htmlspecialchars($matches[2])), '', E_USER_ERROR, __FILE__, __LINE__);
190
191
	$replacement = $values[$matches[2]];
192
193
	switch ($matches[1])
194
	{
195
		case 'int':
196
			if (!is_numeric($replacement) || (string) $replacement !== (string) (int) $replacement)
197
				smf_db_error_backtrace('Wrong value type sent to the database. Integer expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
198
			return (string) (int) $replacement;
199
		break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
200
201
		case 'string':
202
		case 'text':
203
			return sprintf('\'%1$s\'', mysqli_real_escape_string($connection, $replacement));
204
		break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
205
206
		case 'array_int':
207
			if (is_array($replacement))
208
			{
209
				if (empty($replacement))
210
					smf_db_error_backtrace('Database error, given array of integer values is empty. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
211
212
				foreach ($replacement as $key => $value)
213
				{
214
					if (!is_numeric($value) || (string) $value !== (string) (int) $value)
215
						smf_db_error_backtrace('Wrong value type sent to the database. Array of integers expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
216
217
					$replacement[$key] = (string) (int) $value;
218
				}
219
220
				return implode(', ', $replacement);
221
			}
222
			else
223
				smf_db_error_backtrace('Wrong value type sent to the database. Array of integers expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
224
225
		break;
226
227
		case 'array_string':
228
			if (is_array($replacement))
229
			{
230
				if (empty($replacement))
231
					smf_db_error_backtrace('Database error, given array of string values is empty. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
232
233
				foreach ($replacement as $key => $value)
234
					$replacement[$key] = sprintf('\'%1$s\'', mysqli_real_escape_string($connection, $value));
235
236
				return implode(', ', $replacement);
237
			}
238
			else
239
				smf_db_error_backtrace('Wrong value type sent to the database. Array of strings expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
240
		break;
241
242
		case 'date':
243
			if (preg_match('~^(\d{4})-([0-1]?\d)-([0-3]?\d)$~', $replacement, $date_matches) === 1)
244
				return sprintf('\'%04d-%02d-%02d\'', $date_matches[1], $date_matches[2], $date_matches[3]);
245
			else
246
				smf_db_error_backtrace('Wrong value type sent to the database. Date expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
247
		break;
248
249
		case 'time':
250
			if (preg_match('~^([0-1]?\d|2[0-3]):([0-5]\d):([0-5]\d)$~', $replacement, $time_matches) === 1)
251
				return sprintf('\'%02d:%02d:%02d\'', $time_matches[1], $time_matches[2], $time_matches[3]);
252
			else
253
				smf_db_error_backtrace('Wrong value type sent to the database. Time expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
254
		break;
255
256
		case 'float':
257
			if (!is_numeric($replacement))
258
				smf_db_error_backtrace('Wrong value type sent to the database. Floating point number expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
259
			return (string) (float) $replacement;
260
		break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
261
262
		case 'identifier':
263
			// Backticks inside identifiers are supported as of MySQL 4.1. We don't need them for SMF.
264
			return '`' . strtr($replacement, array('`' => '', '.' => '')) . '`';
265
		break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
266
267
		case 'raw':
268
			return $replacement;
269
		break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
270
271
		case 'inet':
272
			if ($replacement == 'null' || $replacement == '')
273
				return 'null';
274
			if (!isValidIP($replacement))
275
				smf_db_error_backtrace('Wrong value type sent to the database. IPv4 or IPv6 expected.(' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
276
			//we don't use the native support of mysql > 5.6.2
277
			return sprintf('unhex(\'%1$s\')', bin2hex(inet_pton($replacement)));
278
279
		case 'array_inet':
280
			if (is_array($replacement))
281
			{
282
				if (empty($replacement))
283
					smf_db_error_backtrace('Database error, given array of IPv4 or IPv6 values is empty. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
284
285
				foreach ($replacement as $key => $value)
286
				{
287
					if ($replacement == 'null' || $replacement == '')
288
						$replacement[$key] = 'null';
289
					if (!isValidIP($value))
290
						smf_db_error_backtrace('Wrong value type sent to the database. IPv4 or IPv6 expected.(' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
291
					$replacement[$key] =  sprintf('unhex(\'%1$s\')', bin2hex(inet_pton($value)));
292
				}
293
294
				return implode(', ', $replacement);
295
			}
296
			else
297
				smf_db_error_backtrace('Wrong value type sent to the database. Array of IPv4 or IPv6 expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
298
		break;
299
300
		default:
301
			smf_db_error_backtrace('Undefined type used in the database query. (' . $matches[1] . ':' . $matches[2] . ')', '', false, __FILE__, __LINE__);
302
		break;
303
	}
304
}
305
306
/**
307
 * Just like the db_query, escape and quote a string, but not executing the query.
308
 *
309
 * @param string $db_string The database string
310
 * @param array $db_values An array of values to be injected into the string
311
 * @param resource $connection = null The connection to use (null to use $db_connection)
312
 * @return string The string with the values inserted
313
 */
314 View Code Duplication
function smf_db_quote($db_string, $db_values, $connection = null)
0 ignored issues
show
Best Practice introduced by
The function smf_db_quote() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L284-302) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
Duplication introduced by
This function 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...
315
{
316
	global $db_callback, $db_connection;
317
318
	// Only bother if there's something to replace.
319
	if (strpos($db_string, '{') !== false)
320
	{
321
		// This is needed by the callback function.
322
		$db_callback = array($db_values, $connection === null ? $db_connection : $connection);
323
324
		// Do the quoting and escaping
325
		$db_string = preg_replace_callback('~{([a-z_]+)(?::([a-zA-Z0-9_-]+))?}~', 'smf_db_replacement__callback', $db_string);
326
327
		// Clear this global variable.
328
		$db_callback = array();
329
	}
330
331
	return $db_string;
332
}
333
334
/**
335
 * Do a query.  Takes care of errors too.
336
 *
337
 * @param string $identifier An identifier. Only used in Postgres when we need to do things differently...
338
 * @param string $db_string The database string
339
 * @param array $db_values = array() The values to be inserted into the string
340
 * @param resource $connection = null The connection to use (null to use $db_connection)
341
 * @return resource|bool Returns a MySQL result resource (for SELECT queries), true (for UPDATE queries) or false if the query failed
342
 */
343
function smf_db_query($identifier, $db_string, $db_values = array(), $connection = null)
0 ignored issues
show
Best Practice introduced by
The function smf_db_query() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L313-449) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
Unused Code introduced by
The parameter $identifier 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...
344
{
345
	global $db_cache, $db_count, $db_connection, $db_show_debug, $time_start;
346
	global $db_unbuffered, $db_callback, $modSettings;
347
348
	// Comments that are allowed in a query are preg_removed.
349
	static $allowed_comments_from = array(
350
		'~\s+~s',
351
		'~/\*!40001 SQL_NO_CACHE \*/~',
352
		'~/\*!40000 USE INDEX \([A-Za-z\_]+?\) \*/~',
353
		'~/\*!40100 ON DUPLICATE KEY UPDATE id_msg = \d+ \*/~',
354
	);
355
	static $allowed_comments_to = array(
356
		' ',
357
		'',
358
		'',
359
		'',
360
	);
361
362
	// Decide which connection to use.
363
	$connection = $connection === null ? $db_connection : $connection;
364
365
	// Get a connection if we are shutting down, sometimes the link is closed before sessions are written
366
	if (!is_object($connection))
367
	{
368
		global $db_server, $db_user, $db_passwd, $db_name, $db_show_debug, $ssi_db_user, $ssi_db_passwd;
369
370
		// Are we in SSI mode?  If so try that username and password first
371
		if (SMF == 'SSI' && !empty($ssi_db_user) && !empty($ssi_db_passwd))
372
		{
373
			if (empty($db_persist))
0 ignored issues
show
Bug introduced by
The variable $db_persist seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
374
				$db_connection = @mysqli_connect($db_server, $ssi_db_user, $ssi_db_passwd);
375
			else
376
				$db_connection = @mysqli_connect('p:' . $db_server, $ssi_db_user, $ssi_db_passwd);
377
		}
378
		// Fall back to the regular username and password if need be
379
		if (!$db_connection)
380
		{
381
			if (empty($db_persist))
382
				$db_connection = @mysqli_connect($db_server, $db_user, $db_passwd);
383
			else
384
				$db_connection = @mysqli_connect('p:' . $db_server, $db_user, $db_passwd);
385
		}
386
387
		if (!$db_connection || !@mysqli_select_db($db_connection, $db_name))
388
			$db_connection = false;
389
390
		$connection = $db_connection;
391
	}
392
393
	// One more query....
394
	$db_count = !isset($db_count) ? 1 : $db_count + 1;
395
396 View Code Duplication
	if (empty($modSettings['disableQueryCheck']) && strpos($db_string, '\'') !== false && empty($db_values['security_override']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
397
		smf_db_error_backtrace('Hacking attempt...', 'Illegal character (\') used in query...', true, __FILE__, __LINE__);
398
399
	// Use "ORDER BY null" to prevent Mysql doing filesorts for Group By clauses without an Order By
400 View Code Duplication
	if (strpos($db_string, 'GROUP BY') !== false && strpos($db_string, 'ORDER BY') === false && preg_match('~^\s+SELECT~i', $db_string))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
401
	{
402
		// Add before LIMIT
403
		if ($pos = strpos($db_string, 'LIMIT '))
404
			$db_string = substr($db_string, 0, $pos) . "\t\t\tORDER BY null\n" . substr($db_string, $pos, strlen($db_string));
405
		else
406
			// Append it.
407
			$db_string .= "\n\t\t\tORDER BY null";
408
	}
409
410 View Code Duplication
	if (empty($db_values['security_override']) && (!empty($db_values) || strpos($db_string, '{db_prefix}') !== false))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
411
	{
412
		// Pass some values to the global space for use in the callback function.
413
		$db_callback = array($db_values, $connection);
414
415
		// Inject the values passed to this function.
416
		$db_string = preg_replace_callback('~{([a-z_]+)(?::([a-zA-Z0-9_-]+))?}~', 'smf_db_replacement__callback', $db_string);
417
418
		// This shouldn't be residing in global space any longer.
419
		$db_callback = array();
420
	}
421
422
	// Debugging.
423 View Code Duplication
	if (isset($db_show_debug) && $db_show_debug === true)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
424
	{
425
		// Get the file and line number this function was called.
426
		list ($file, $line) = smf_db_error_backtrace('', '', 'return', __FILE__, __LINE__);
427
428
		// Initialize $db_cache if not already initialized.
429
		if (!isset($db_cache))
430
			$db_cache = array();
431
432
		if (!empty($_SESSION['debug_redirect']))
433
		{
434
			$db_cache = array_merge($_SESSION['debug_redirect'], $db_cache);
435
			$db_count = count($db_cache) + 1;
436
			$_SESSION['debug_redirect'] = array();
437
		}
438
439
		// Don't overload it.
440
		$st = microtime();
441
		$db_cache[$db_count]['q'] = $db_count < 50 ? $db_string : '...';
442
		$db_cache[$db_count]['f'] = $file;
443
		$db_cache[$db_count]['l'] = $line;
444
		$db_cache[$db_count]['s'] = array_sum(explode(' ', $st)) - array_sum(explode(' ', $time_start));
445
	}
446
447
	// First, we clean strings out of the query, reduce whitespace, lowercase, and trim - so we can check it over.
448 View Code Duplication
	if (empty($modSettings['disableQueryCheck']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
449
	{
450
		$clean = '';
451
		$old_pos = 0;
452
		$pos = -1;
453
		while (true)
454
		{
455
			$pos = strpos($db_string, '\'', $pos + 1);
456
			if ($pos === false)
457
				break;
458
			$clean .= substr($db_string, $old_pos, $pos - $old_pos);
459
460
			while (true)
461
			{
462
				$pos1 = strpos($db_string, '\'', $pos + 1);
463
				$pos2 = strpos($db_string, '\\', $pos + 1);
464
				if ($pos1 === false)
465
					break;
466
				elseif ($pos2 === false || $pos2 > $pos1)
467
				{
468
					$pos = $pos1;
469
					break;
470
				}
471
472
				$pos = $pos2 + 1;
473
			}
474
			$clean .= ' %s ';
475
476
			$old_pos = $pos + 1;
477
		}
478
		$clean .= substr($db_string, $old_pos);
479
		$clean = trim(strtolower(preg_replace($allowed_comments_from, $allowed_comments_to, $clean)));
480
481
		// Comments?  We don't use comments in our queries, we leave 'em outside!
482
		if (strpos($clean, '/*') > 2 || strpos($clean, '--') !== false || strpos($clean, ';') !== false)
483
			$fail = true;
484
		// Trying to change passwords, slow us down, or something?
485
		elseif (strpos($clean, 'sleep') !== false && preg_match('~(^|[^a-z])sleep($|[^[_a-z])~s', $clean) != 0)
486
			$fail = true;
487
		elseif (strpos($clean, 'benchmark') !== false && preg_match('~(^|[^a-z])benchmark($|[^[a-z])~s', $clean) != 0)
488
			$fail = true;
489
490
		if (!empty($fail) && function_exists('log_error'))
491
			smf_db_error_backtrace('Hacking attempt...', 'Hacking attempt...' . "\n" . $db_string, E_USER_ERROR, __FILE__, __LINE__);
492
	}
493
494
	if (empty($db_unbuffered))
495
		$ret = @mysqli_query($connection, $db_string);
496
	else
497
		$ret = @mysqli_query($connection, $db_string, MYSQLI_USE_RESULT);
498
499 View Code Duplication
	if ($ret === false && empty($db_values['db_error_skip']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
500
		$ret = smf_db_error($db_string, $connection);
501
502
	// Debugging.
503 View Code Duplication
	if (isset($db_show_debug) && $db_show_debug === true)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
504
		$db_cache[$db_count]['t'] = array_sum(explode(' ', microtime())) - array_sum(explode(' ', $st));
0 ignored issues
show
Bug introduced by
The variable $st 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...
505
506
	return $ret;
507
}
508
509
/**
510
 * affected_rows
511
 * @param resource $connection A connection to use (if null, $db_connection is used)
512
 * @return int The number of rows affected by the last query
513
 */
514
function smf_db_affected_rows($connection = null)
0 ignored issues
show
Best Practice introduced by
The function smf_db_affected_rows() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L456-461) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
515
{
516
	global $db_connection;
517
518
	return mysqli_affected_rows($connection === null ? $db_connection : $connection);
519
}
520
521
/**
522
 * Gets the ID of the most recently inserted row.
523
 *
524
 * @param string $table The table (only used for Postgres)
525
 * @param string $field = null The specific field (not used here)
526
 * @param resource $connection = null The connection (if null, $db_connection is used)
527
 * @return int The ID of the most recently inserted row
528
 */
529 View Code Duplication
function smf_db_insert_id($table, $field = null, $connection = null)
0 ignored issues
show
Best Practice introduced by
The function smf_db_insert_id() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L471-479) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
Unused Code introduced by
The parameter $field 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...
Duplication introduced by
This function 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...
530
{
531
	global $db_connection, $db_prefix;
532
533
	$table = str_replace('{db_prefix}', $db_prefix, $table);
0 ignored issues
show
Unused Code introduced by
$table is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
534
535
	// MySQL doesn't need the table or field information.
536
	return mysqli_insert_id($connection === null ? $db_connection : $connection);
537
}
538
539
/**
540
 * Do a transaction.
541
 *
542
 * @param string $type The step to perform (i.e. 'begin', 'commit', 'rollback')
543
 * @param resource $connection The connection to use (if null, $db_connection is used)
544
 * @return bool True if successful, false otherwise
545
 */
546 View Code Duplication
function smf_db_transaction($type = 'commit', $connection = null)
0 ignored issues
show
Best Practice introduced by
The function smf_db_transaction() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L488-503) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
Duplication introduced by
This function 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...
547
{
548
	global $db_connection;
549
550
	// Decide which connection to use
551
	$connection = $connection === null ? $db_connection : $connection;
552
553
	if ($type == 'begin')
554
		return @mysqli_query($connection, 'BEGIN');
555
	elseif ($type == 'rollback')
556
		return @mysqli_query($connection, 'ROLLBACK');
557
	elseif ($type == 'commit')
558
		return @mysqli_query($connection, 'COMMIT');
559
560
	return false;
561
}
562
563
/**
564
 * Database error!
565
 * Backtrace, log, try to fix.
566
 *
567
 * @param string $db_string The DB string
568
 * @param object $connection The connection to use (if null, $db_connection is used)
569
 */
570 View Code Duplication
function smf_db_error($db_string, $connection = null)
0 ignored issues
show
Best Practice introduced by
The function smf_db_error() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L512-694) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
Duplication introduced by
This function 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...
571
{
572
	global $txt, $context, $sourcedir, $webmaster_email, $modSettings;
573
	global $db_connection, $db_last_error, $db_persist;
574
	global $db_server, $db_user, $db_passwd, $db_name, $db_show_debug, $ssi_db_user, $ssi_db_passwd;
575
	global $smcFunc;
576
577
	// Get the file and line numbers.
578
	list ($file, $line) = smf_db_error_backtrace('', '', 'return', __FILE__, __LINE__);
579
580
	// Decide which connection to use
581
	$connection = $connection === null ? $db_connection : $connection;
582
583
	// This is the error message...
584
	$query_error = mysqli_error($connection);
585
	$query_errno = mysqli_errno($connection);
586
587
	// Error numbers:
588
	//    1016: Can't open file '....MYI'
589
	//    1030: Got error ??? from table handler.
590
	//    1034: Incorrect key file for table.
591
	//    1035: Old key file for table.
592
	//    1205: Lock wait timeout exceeded.
593
	//    1213: Deadlock found.
594
	//    2006: Server has gone away.
595
	//    2013: Lost connection to server during query.
596
597
	// Log the error.
598
	if ($query_errno != 1213 && $query_errno != 1205 && function_exists('log_error'))
599
		log_error($txt['database_error'] . ': ' . $query_error . (!empty($modSettings['enableErrorQueryLogging']) ? "\n\n$db_string" : ''), 'database', $file, $line);
600
601
	// Database error auto fixing ;).
602
	if (function_exists('cache_get_data') && (!isset($modSettings['autoFixDatabase']) || $modSettings['autoFixDatabase'] == '1'))
603
	{
604
		// Force caching on, just for the error checking.
605
		$old_cache = @$modSettings['cache_enable'];
606
		$modSettings['cache_enable'] = '1';
607
608
		if (($temp = cache_get_data('db_last_error', 600)) !== null)
609
			$db_last_error = max(@$db_last_error, $temp);
610
611
		if (@$db_last_error < time() - 3600 * 24 * 3)
612
		{
613
			// We know there's a problem... but what?  Try to auto detect.
614
			if ($query_errno == 1030 && strpos($query_error, ' 127 ') !== false)
615
			{
616
				preg_match_all('~(?:[\n\r]|^)[^\']+?(?:FROM|JOIN|UPDATE|TABLE) ((?:[^\n\r(]+?(?:, )?)*)~s', $db_string, $matches);
617
618
				$fix_tables = array();
619
				foreach ($matches[1] as $tables)
620
				{
621
					$tables = array_unique(explode(',', $tables));
622
					foreach ($tables as $table)
623
					{
624
						// Now, it's still theoretically possible this could be an injection.  So backtick it!
625
						if (trim($table) != '')
626
							$fix_tables[] = '`' . strtr(trim($table), array('`' => '')) . '`';
627
					}
628
				}
629
630
				$fix_tables = array_unique($fix_tables);
631
			}
632
			// Table crashed.  Let's try to fix it.
633
			elseif ($query_errno == 1016)
634
			{
635
				if (preg_match('~\'([^\.\']+)~', $query_error, $match) != 0)
636
					$fix_tables = array('`' . $match[1] . '`');
637
			}
638
			// Indexes crashed.  Should be easy to fix!
639
			elseif ($query_errno == 1034 || $query_errno == 1035)
640
			{
641
				preg_match('~\'([^\']+?)\'~', $query_error, $match);
642
				$fix_tables = array('`' . $match[1] . '`');
643
			}
644
		}
645
646
		// Check for errors like 145... only fix it once every three days, and send an email. (can't use empty because it might not be set yet...)
647
		if (!empty($fix_tables))
648
		{
649
			// Subs-Admin.php for updateSettingsFile(), Subs-Post.php for sendmail().
650
			require_once($sourcedir . '/Subs-Admin.php');
651
			require_once($sourcedir . '/Subs-Post.php');
652
653
			// Make a note of the REPAIR...
654
			cache_put_data('db_last_error', time(), 600);
655
			if (($temp = cache_get_data('db_last_error', 600)) === null)
656
				updateSettingsFile(array('db_last_error' => time()));
657
658
			// Attempt to find and repair the broken table.
659
			foreach ($fix_tables as $table)
660
				$smcFunc['db_query']('', "
661
					REPAIR TABLE $table", false, false);
662
663
			// And send off an email!
664
			sendmail($webmaster_email, $txt['database_error'], $txt['tried_to_repair'], null, 'dberror');
665
666
			$modSettings['cache_enable'] = $old_cache;
667
668
			// Try the query again...?
669
			$ret = $smcFunc['db_query']('', $db_string, false, false);
670
			if ($ret !== false)
671
				return $ret;
672
		}
673
		else
674
			$modSettings['cache_enable'] = $old_cache;
675
676
		// Check for the "lost connection" or "deadlock found" errors - and try it just one more time.
677
		if (in_array($query_errno, array(1205, 1213, 2006, 2013)))
678
		{
679
			if (in_array($query_errno, array(2006, 2013)) && $db_connection == $connection)
680
			{
681
				// Are we in SSI mode?  If so try that username and password first
682
				if (SMF == 'SSI' && !empty($ssi_db_user) && !empty($ssi_db_passwd))
683
				{
684
					if (empty($db_persist))
685
						$db_connection = @mysqli_connect($db_server, $ssi_db_user, $ssi_db_passwd);
686
					else
687
						$db_connection = @mysqli_connect('p:' . $db_server, $ssi_db_user, $ssi_db_passwd);
688
				}
689
				// Fall back to the regular username and password if need be
690
				if (!$db_connection)
691
				{
692
					if (empty($db_persist))
693
						$db_connection = @mysqli_connect($db_server, $db_user, $db_passwd);
694
					else
695
						$db_connection = @mysqli_connect('p:' . $db_server, $db_user, $db_passwd);
696
				}
697
698
				if (!$db_connection || !@mysqli_select_db($db_connection, $db_name))
699
					$db_connection = false;
700
			}
701
702
			if ($db_connection)
703
			{
704
				// Try a deadlock more than once more.
705
				for ($n = 0; $n < 4; $n++)
706
				{
707
					$ret = $smcFunc['db_query']('', $db_string, false, false);
708
709
					$new_errno = mysqli_errno($db_connection);
710
					if ($ret !== false || in_array($new_errno, array(1205, 1213)))
711
						break;
712
				}
713
714
				// If it failed again, shucks to be you... we're not trying it over and over.
715
				if ($ret !== false)
716
					return $ret;
0 ignored issues
show
Bug introduced by
The variable $ret 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...
717
			}
718
		}
719
		// Are they out of space, perhaps?
720
		elseif ($query_errno == 1030 && (strpos($query_error, ' -1 ') !== false || strpos($query_error, ' 28 ') !== false || strpos($query_error, ' 12 ') !== false))
721
		{
722
			if (!isset($txt))
723
				$query_error .= ' - check database storage space.';
724
			else
725
			{
726
				if (!isset($txt['mysql_error_space']))
727
					loadLanguage('Errors');
728
729
				$query_error .= !isset($txt['mysql_error_space']) ? ' - check database storage space.' : $txt['mysql_error_space'];
730
			}
731
		}
732
	}
733
734
	// Nothing's defined yet... just die with it.
735
	if (empty($context) || empty($txt))
736
		die($query_error);
737
738
	// Show an error message, if possible.
739
	$context['error_title'] = $txt['database_error'];
740
	if (allowedTo('admin_forum'))
741
		$context['error_message'] = nl2br($query_error) . '<br>' . $txt['file'] . ': ' . $file . '<br>' . $txt['line'] . ': ' . $line;
742
	else
743
		$context['error_message'] = $txt['try_again'];
744
745
	if (allowedTo('admin_forum') && isset($db_show_debug) && $db_show_debug === true)
746
	{
747
		$context['error_message'] .= '<br><br>' . nl2br($db_string);
748
	}
749
750
	// It's already been logged... don't log it again.
751
	fatal_error($context['error_message'], false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

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...
752
}
753
754
/**
755
 * Inserts data into a table
756
 *
757
 * @param string $method The insert method - can be 'replace', 'ignore' or 'insert'
758
 * @param string $table The table we're inserting the data into
759
 * @param array $columns An array of the columns we're inserting the data into. Should contain 'column' => 'datatype' pairs
760
 * @param array $data The data to insert
761
 * @param array $keys The keys for the table
762
 * @param bool $disable_trans Whether to disable transactions
763
 * @param object $connection The connection to use (if null, $db_connection is used)
764
 */
765 View Code Duplication
function smf_db_insert($method = 'replace', $table, $columns, $data, $keys, $disable_trans = false, $connection = null)
0 ignored issues
show
Best Practice introduced by
The function smf_db_insert() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L707-759) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
Unused Code introduced by
The parameter $keys 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 $disable_trans 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...
Duplication introduced by
This function 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...
766
{
767
	global $smcFunc, $db_connection, $db_prefix;
768
769
	$connection = $connection === null ? $db_connection : $connection;
770
771
	// With nothing to insert, simply return.
772
	if (empty($data))
773
		return;
774
775
	// Replace the prefix holder with the actual prefix.
776
	$table = str_replace('{db_prefix}', $db_prefix, $table);
777
778
	// Inserting data as a single row can be done as a single array.
779
	if (!is_array($data[array_rand($data)]))
780
		$data = array($data);
781
782
	// Create the mold for a single row insert.
783
	$insertData = '(';
784
	foreach ($columns as $columnName => $type)
785
	{
786
		// Are we restricting the length?
787
		if (strpos($type, 'string-') !== false)
788
			$insertData .= sprintf('SUBSTRING({string:%1$s}, 1, ' . substr($type, 7) . '), ', $columnName);
789
		else
790
			$insertData .= sprintf('{%1$s:%2$s}, ', $type, $columnName);
791
	}
792
	$insertData = substr($insertData, 0, -2) . ')';
793
794
	// Create an array consisting of only the columns.
795
	$indexed_columns = array_keys($columns);
796
797
	// Here's where the variables are injected to the query.
798
	$insertRows = array();
799
	foreach ($data as $dataRow)
800
		$insertRows[] = smf_db_quote($insertData, array_combine($indexed_columns, $dataRow), $connection);
801
802
	// Determine the method of insertion.
803
	$queryTitle = $method == 'replace' ? 'REPLACE' : ($method == 'ignore' ? 'INSERT IGNORE' : 'INSERT');
804
805
	// Do the insert.
806
	$smcFunc['db_query']('', '
807
		' . $queryTitle . ' INTO ' . $table . '(`' . implode('`, `', $indexed_columns) . '`)
808
		VALUES
809
			' . implode(',
810
			', $insertRows),
811
		array(
812
			'security_override' => true,
813
			'db_error_skip' => $table === $db_prefix . 'log_errors',
814
		),
815
		$connection
816
	);
817
}
818
819
/**
820
 * This function tries to work out additional error information from a back trace.
821
 *
822
 * @param string $error_message The error message
823
 * @param string $log_message The message to log
824
 * @param string|bool $error_type What type of error this is
825
 * @param string $file The file the error occurred in
826
 * @param int $line What line of $file the code which generated the error is on
827
 * @return void|array Returns an array with the file and line if $error_type is 'return'
828
 */
829 View Code Duplication
function smf_db_error_backtrace($error_message, $log_message = '', $error_type = false, $file = null, $line = null)
0 ignored issues
show
Best Practice introduced by
The function smf_db_error_backtrace() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L771-811) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
Duplication introduced by
This function 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...
830
{
831
	if (empty($log_message))
832
		$log_message = $error_message;
833
834
	foreach (debug_backtrace() as $step)
835
	{
836
		// Found it?
837
		if (strpos($step['function'], 'query') === false && !in_array(substr($step['function'], 0, 7), array('smf_db_', 'preg_re', 'db_erro', 'call_us')) && strpos($step['function'], '__') !== 0)
838
		{
839
			$log_message .= '<br>Function: ' . $step['function'];
840
			break;
841
		}
842
843
		if (isset($step['line']))
844
		{
845
			$file = $step['file'];
846
			$line = $step['line'];
847
		}
848
	}
849
850
	// A special case - we want the file and line numbers for debugging.
851
	if ($error_type == 'return')
852
		return array($file, $line);
853
854
	// Is always a critical error.
855
	if (function_exists('log_error'))
856
		log_error($log_message, 'critical', $file, $line);
857
858
	if (function_exists('fatal_error'))
859
	{
860
		fatal_error($error_message, false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

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...
861
862
		// Cannot continue...
863
		exit;
864
	}
865
	elseif ($error_type)
866
		trigger_error($error_message . ($line !== null ? '<em>(' . basename($file) . '-' . $line . ')</em>' : ''), $error_type);
867
	else
868
		trigger_error($error_message . ($line !== null ? '<em>(' . basename($file) . '-' . $line . ')</em>' : ''));
869
}
870
871
/**
872
 * Escape the LIKE wildcards so that they match the character and not the wildcard.
873
 *
874
 * @param string $string The string to escape
875
 * @param bool $translate_human_wildcards If true, turns human readable wildcards into SQL wildcards.
876
 * @return string The escaped string
877
 */
878 View Code Duplication
function smf_db_escape_wildcard_string($string, $translate_human_wildcards=false)
0 ignored issues
show
Best Practice introduced by
The function smf_db_escape_wildcard_string() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L820-834) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
Duplication introduced by
This function 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...
879
{
880
	$replacements = array(
881
		'%' => '\%',
882
		'_' => '\_',
883
		'\\' => '\\\\',
884
	);
885
886
	if ($translate_human_wildcards)
887
		$replacements += array(
888
			'*' => '%',
889
		);
890
891
	return strtr($string, $replacements);
892
}
893
894
/**
895
 * Validates whether the resource is a valid mysqli instance.
896
 * Mysqli uses objects rather than resource. https://bugs.php.net/bug.php?id=42797
897
 *
898
 * @param mixed $result The string to test
899
 * @return bool True if it is, false otherwise
900
 */
901
function smf_is_resource($result)
902
{
903
	if ($result instanceof mysqli_result)
904
		return true;
905
906
	return false;
907
}
908
909
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...