Completed
Pull Request — release-2.1 (#5048)
by Mathias
06:59 queued 42s
created

Subs-Db-postgresql.php ➔ smf_db_data_seek()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 8
rs 10
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 2018 Simple Machines and individual contributors
11
 * @license http://www.simplemachines.org/about/smf/license.php BSD
12
 *
13
 * @version 2.1 Beta 4
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
 * @see Subs-Db-mysql.php#smf_db_initiate
23
 *
24
 * @param string $db_server The database server
25
 * @param string $db_name The name of the database
26
 * @param string $db_user The database username
27
 * @param string $db_passwd The database password
28
 * @param string $db_prefix The table prefix
29
 * @param array $db_options An array of database options
30
 * @return null|resource Returns null on failure if $db_options['non_fatal'] is true or a PostgreSQL connection resource handle if the connection was successful.
31
 */
32
function smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, &$db_prefix, $db_options = array())
0 ignored issues
show
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...
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-109) 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...
33
{
34
	global $smcFunc;
35
36
	// Map some database specific functions, only do this once.
37
	if (!isset($smcFunc['db_fetch_assoc']))
38
		$smcFunc += array(
39
			'db_query'                  => 'smf_db_query',
40
			'db_quote'                  => 'smf_db_quote',
41
			'db_insert'                 => 'smf_db_insert',
42
			'db_insert_id'              => 'smf_db_insert_id',
43
			'db_fetch_assoc'            => 'pg_fetch_assoc',
44
			'db_fetch_row'              => 'pg_fetch_row',
45
			'db_free_result'            => 'pg_free_result',
46
			'db_num_rows'               => 'pg_num_rows',
47
			'db_data_seek'              => 'pg_result_seek',
48
			'db_num_fields'             => 'pg_num_fields',
49
			'db_escape_string'          => 'smf_db_escape_string',
50
			'db_unescape_string'        => 'stripslashes',
51
			'db_server_info'            => 'smf_db_version',
52
			'db_affected_rows'          => 'smf_db_affected_rows',
53
			'db_transaction'            => 'smf_db_transaction',
54
			'db_error'                  => 'pg_last_error',
55
			'db_select_db'              => 'smf_db_select_db',
56
			'db_title'                  => 'PostgreSQL',
57
			'db_sybase'                 => true,
58
			'db_case_sensitive'         => true,
59
			'db_escape_wildcard_string' => 'smf_db_escape_wildcard_string',
60
			'db_is_resource'            => 'is_resource',
61
			'db_mb4'                    => true,
62
			'db_ping'                   => 'pg_ping',
63
			'db_fetch_all'              => 'smf_db_fetch_all',
64
			'db_error_insert'           => 'smf_db_error_insert',
65
			'db_custom_order'           => 'smf_db_custom_order',
66
			'db_native_replace'         => 'smf_db_native_replace',
67
			'db_cte_support'            => 'smf_db_cte_support',
68
		);
69
70
	// We are not going to make it very far without these.
71
	if (!function_exists('pg_pconnect'))
72
		display_db_error();
73
74
	if (!empty($db_options['persist']))
75
		$connection = @pg_pconnect((empty($db_server) ? '' : 'host=' . $db_server . ' ') . 'dbname=' . $db_name . ' user=\'' . $db_user . '\' password=\'' . $db_passwd . '\'' . (empty($db_options['port']) ? '' : ' port=\'' . $db_options['port'] . '\''));
76
	else
77
		$connection = @pg_connect((empty($db_server) ? '' : 'host=' . $db_server . ' ') . 'dbname=' . $db_name . ' user=\'' . $db_user . '\' password=\'' . $db_passwd . '\'' . (empty($db_options['port']) ? '' : ' port=\'' . $db_options['port'] . '\''));
78
79
	// Something's wrong, show an error if its fatal (which we assume it is)
80
	if (!$connection)
81
	{
82
		if (!empty($db_options['non_fatal']))
83
		{
84
			return null;
85
		}
86
		else
87
		{
88
			display_db_error();
89
		}
90
	}
91
92
	if (!empty($db_options['db_mb4']))
93
		$smcFunc['db_mb4'] = (bool) $db_options['db_mb4'];
94
95
	return $connection;
96
}
97
98
/**
99
 * Extend the database functionality. It calls the respective file's init
100
 * to add the implementations in that file to $smcFunc array.
101
 *
102
 * @param string $type Indicates which additional file to load. ('extra', 'packages')
103
 */
104 View Code Duplication
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 (L117-125) 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...
105
{
106
	global $sourcedir, $db_type;
107
108
	require_once($sourcedir . '/Db' . strtoupper($type[0]) . substr($type, 1) . '-' . $db_type . '.php');
109
	$initFunc = 'db_' . $type . '_init';
110
	$initFunc();
111
}
112
113
/**
114
 * Fix the database prefix if necessary.
115
 * Does nothing on PostgreSQL
116
 *
117
 * @param string $db_prefix The database prefix
118
 * @param string $db_name The database name
119
 */
120
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 (L133-136) 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...
Unused Code introduced by
The parameter $db_name 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...
121
{
122
	return;
123
}
124
125
/**
126
 * Callback for preg_replace_callback on the query.
127
 * It allows to replace on the fly a few pre-defined strings, for convenience ('query_see_board', 'query_wanna_see_board', etc), with
128
 * their current values from $user_info.
129
 * In addition, it performs checks and sanitization on the values sent to the database.
130
 *
131
 * @param array $matches The matches from preg_replace_callback
132
 * @return string The appropriate string depending on $matches[1]
133
 */
134
function smf_db_replacement__callback($matches)
0 ignored issues
show
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 (L172-320) 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...
135
{
136
	global $db_callback, $user_info, $db_prefix, $smcFunc;
137
138
	list ($values, $connection) = $db_callback;
0 ignored issues
show
Unused Code introduced by
The assignment to $connection is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
139
140
	if ($matches[1] === 'db_prefix')
141
		return $db_prefix;
142
143 View Code Duplication
	if (isset($user_info[$matches[1]]) && strpos($matches[1], 'query_') !== false)
144
		return $user_info[$matches[1]];
145
146
	if ($matches[1] === 'empty')
147
		return '\'\'';
148
149
	if (!isset($matches[2]))
150
		smf_db_error_backtrace('Invalid value inserted or no type specified.', '', E_USER_ERROR, __FILE__, __LINE__);
151
152
	if ($matches[1] === 'literal')
153
		return '\'' . pg_escape_string($matches[2]) . '\'';
154
155 View Code Duplication
	if (!isset($values[$matches[2]]))
156
		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__);
157
158
	$replacement = $values[$matches[2]];
159
160
	switch ($matches[1])
161
	{
162 View Code Duplication
		case 'int':
163
			if (!is_numeric($replacement) || (string) $replacement !== (string) (int) $replacement)
164
				smf_db_error_backtrace('Wrong value type sent to the database. Integer expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
165
			return (string) (int) $replacement;
166
		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...
167
168
		case 'string':
169
		case 'text':
170
			return sprintf('\'%1$s\'', pg_escape_string($replacement));
171
		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...
172
173 View Code Duplication
		case 'array_int':
174
			if (is_array($replacement))
175
			{
176
				if (empty($replacement))
177
					smf_db_error_backtrace('Database error, given array of integer values is empty. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
178
179
				foreach ($replacement as $key => $value)
180
				{
181
					if (!is_numeric($value) || (string) $value !== (string) (int) $value)
182
						smf_db_error_backtrace('Wrong value type sent to the database. Array of integers expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
183
184
					$replacement[$key] = (string) (int) $value;
185
				}
186
187
				return implode(', ', $replacement);
188
			}
189
			else
190
				smf_db_error_backtrace('Wrong value type sent to the database. Array of integers expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
191
192
		break;
193
194 View Code Duplication
		case 'array_string':
195
			if (is_array($replacement))
196
			{
197
				if (empty($replacement))
198
					smf_db_error_backtrace('Database error, given array of string values is empty. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
199
200
				foreach ($replacement as $key => $value)
201
					$replacement[$key] = sprintf('\'%1$s\'', pg_escape_string($value));
202
203
				return implode(', ', $replacement);
204
			}
205
			else
206
				smf_db_error_backtrace('Wrong value type sent to the database. Array of strings expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
207
		break;
208
209 View Code Duplication
		case 'date':
210
			if (preg_match('~^(\d{4})-([0-1]?\d)-([0-3]?\d)$~', $replacement, $date_matches) === 1)
211
				return sprintf('\'%04d-%02d-%02d\'', $date_matches[1], $date_matches[2], $date_matches[3]).'::date';
212
			else
213
				smf_db_error_backtrace('Wrong value type sent to the database. Date expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
214
		break;
215
216 View Code Duplication
		case 'time':
217
			if (preg_match('~^([0-1]?\d|2[0-3]):([0-5]\d):([0-5]\d)$~', $replacement, $time_matches) === 1)
218
				return sprintf('\'%02d:%02d:%02d\'', $time_matches[1], $time_matches[2], $time_matches[3]).'::time';
219
			else
220
				smf_db_error_backtrace('Wrong value type sent to the database. Time expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
221
		break;
222
223 View Code Duplication
		case 'datetime':
224
			if (preg_match('~^(\d{4})-([0-1]?\d)-([0-3]?\d) ([0-1]?\d|2[0-3]):([0-5]\d):([0-5]\d)$~', $replacement, $datetime_matches) === 1)
225
				return 'to_timestamp('.
226
					sprintf('\'%04d-%02d-%02d %02d:%02d:%02d\'', $datetime_matches[1], $datetime_matches[2], $datetime_matches[3], $datetime_matches[4], $datetime_matches[5] ,$datetime_matches[6]).
227
					',\'YYYY-MM-DD HH24:MI:SS\')';
228
			else
229
				smf_db_error_backtrace('Wrong value type sent to the database. Datetime expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
230
		break;
231
232 View Code Duplication
		case 'float':
233
			if (!is_numeric($replacement))
234
				smf_db_error_backtrace('Wrong value type sent to the database. Floating point number expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
235
			return (string) (float) $replacement;
236
		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...
237
238 View Code Duplication
		case 'identifier':
239
			return '"' . strtr($replacement, array('`' => '', '.' => '"."')) . '"';
240
		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...
241
242
		case 'raw':
243
			return $replacement;
244
		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...
245
246 View Code Duplication
		case 'inet':
247
			if ($replacement == 'null' || $replacement == '')
248
				return 'null';
249
			if (inet_pton($replacement) === false)
250
				smf_db_error_backtrace('Wrong value type sent to the database. IPv4 or IPv6 expected.(' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
251
			return sprintf('\'%1$s\'::inet', pg_escape_string($replacement));
252
253 View Code Duplication
		case 'array_inet':
254
			if (is_array($replacement))
255
			{
256
				if (empty($replacement))
257
					smf_db_error_backtrace('Database error, given array of IPv4 or IPv6 values is empty. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
258
259
				foreach ($replacement as $key => $value)
260
				{
261
					if ($replacement == 'null' || $replacement == '')
262
						$replacement[$key] = 'null';
263
					if (!isValidIP($value))
264
						smf_db_error_backtrace('Wrong value type sent to the database. IPv4 or IPv6 expected.(' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
265
					$replacement[$key] = sprintf('\'%1$s\'::inet', pg_escape_string($value));
266
				}
267
268
				return implode(', ', $replacement);
269
			}
270
			else
271
				smf_db_error_backtrace('Wrong value type sent to the database. Array of IPv4 or IPv6 expected. (' . $matches[2] . ')', '', E_USER_ERROR, __FILE__, __LINE__);
272
		break;
273
274 View Code Duplication
		default:
275
			smf_db_error_backtrace('Undefined type used in the database query. (' . $matches[1] . ':' . $matches[2] . ')', '', false, __FILE__, __LINE__);
276
		break;
277
	}
278
}
279
280
/**
281
 * Just like the db_query, escape and quote a string, but not executing the query.
282
 *
283
 * @param string $db_string The database string
284
 * @param array $db_values An array of values to be injected into the string
285
 * @param resource $connection = null The connection to use (null to use $db_connection)
0 ignored issues
show
Documentation introduced by
Should the type for parameter $connection not be resource|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
286
 * @return string The string with the values inserted
287
 */
288 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 (L330-348) 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...
289
{
290
	global $db_callback, $db_connection;
291
292
	// Only bother if there's something to replace.
293
	if (strpos($db_string, '{') !== false)
294
	{
295
		// This is needed by the callback function.
296
		$db_callback = array($db_values, $connection === null ? $db_connection : $connection);
297
298
		// Do the quoting and escaping
299
		$db_string = preg_replace_callback('~{([a-z_]+)(?::([a-zA-Z0-9_-]+))?}~', 'smf_db_replacement__callback', $db_string);
300
301
		// Clear this global variable.
302
		$db_callback = array();
303
	}
304
305
	return $db_string;
306
}
307
308
/**
309
 * Do a query.  Takes care of errors too.
310
 * Special queries may need additional replacements to be appropriate
311
 * for PostgreSQL.
312
 *
313
 * @param string $identifier An identifier. Only used in Postgres when we need to do things differently...
314
 * @param string $db_string The database string
315
 * @param array $db_values = array() The values to be inserted into the string
316
 * @param resource $connection = null The connection to use (null to use $db_connection)
0 ignored issues
show
Documentation introduced by
Should the type for parameter $connection not be resource|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
317
 * @return resource|bool Returns a MySQL result resource (for SELECT queries), true (for UPDATE queries) or false if the query failed
318
 */
319
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 (L359-496) 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...
320
{
321
	global $db_cache, $db_count, $db_connection, $db_show_debug, $time_start;
322
	global $db_callback, $db_last_result, $db_replace_result, $modSettings;
323
324
	// Decide which connection to use.
325
	$connection = $connection === null ? $db_connection : $connection;
326
327
	// Special queries that need processing.
328
	$replacements = array(
329
		'consolidate_spider_stats' => array(
330
			'~MONTH\(log_time\), DAYOFMONTH\(log_time\)~' => 'MONTH(CAST(CAST(log_time AS abstime) AS timestamp)), DAYOFMONTH(CAST(CAST(log_time AS abstime) AS timestamp))',
331
		),
332
		'get_random_number' => array(
333
			'~RAND~' => 'RANDOM',
334
		),
335
		'insert_log_search_topics' => array(
336
			'~NOT RLIKE~' => '!~',
337
		),
338
		'insert_log_search_results_no_index' => array(
339
			'~NOT RLIKE~' => '!~',
340
		),
341
		'insert_log_search_results_subject' => array(
342
			'~NOT RLIKE~' => '!~',
343
		),
344
		'profile_board_stats' => array(
345
			'~COUNT\(\*\) \/ MAX\(b.num_posts\)~' => 'CAST(COUNT(*) AS DECIMAL) / CAST(b.num_posts AS DECIMAL)',
346
		),
347
	);
348
349
	// Special optimizer Hints
350
	$query_opt = array(
351
		'load_board_info' => array(
352
			'join_collapse_limit' => 1,
353
		),
354
		'calendar_get_events' => array(
355
			'enable_seqscan' => 'off',
356
		),
357
	);
358
359 View Code Duplication
	if (isset($replacements[$identifier]))
360
		$db_string = preg_replace(array_keys($replacements[$identifier]), array_values($replacements[$identifier]), $db_string);
361
362
	// Limits need to be a little different.
363
	$db_string = preg_replace('~\sLIMIT\s(\d+|{int:.+}),\s*(\d+|{int:.+})\s*$~i', 'LIMIT $2 OFFSET $1', $db_string);
364
365
	if (trim($db_string) == '')
366
		return false;
367
368
	// Comments that are allowed in a query are preg_removed.
369
	static $allowed_comments_from = array(
370
		'~\s+~s',
371
		'~/\*!40001 SQL_NO_CACHE \*/~',
372
		'~/\*!40000 USE INDEX \([A-Za-z\_]+?\) \*/~',
373
		'~/\*!40100 ON DUPLICATE KEY UPDATE id_msg = \d+ \*/~',
374
	);
375
	static $allowed_comments_to = array(
376
		' ',
377
		'',
378
		'',
379
		'',
380
	);
381
382
	// One more query....
383
	$db_count = !isset($db_count) ? 1 : $db_count + 1;
384
	$db_replace_result = 0;
385
386 View Code Duplication
	if (empty($modSettings['disableQueryCheck']) && strpos($db_string, '\'') !== false && empty($db_values['security_override']))
387
		smf_db_error_backtrace('Hacking attempt...', 'Illegal character (\') used in query...', true, __FILE__, __LINE__);
388
389 View Code Duplication
	if (empty($db_values['security_override']) && (!empty($db_values) || strpos($db_string, '{db_prefix}') !== false))
390
	{
391
		// Pass some values to the global space for use in the callback function.
392
		$db_callback = array($db_values, $connection);
393
394
		// Inject the values passed to this function.
395
		$db_string = preg_replace_callback('~{([a-z_]+)(?::([a-zA-Z0-9_-]+))?}~', 'smf_db_replacement__callback', $db_string);
396
397
		// This shouldn't be residing in global space any longer.
398
		$db_callback = array();
399
	}
400
401
	// First, we clean strings out of the query, reduce whitespace, lowercase, and trim - so we can check it over.
402 View Code Duplication
	if (empty($modSettings['disableQueryCheck']))
403
	{
404
		$clean = '';
405
		$old_pos = 0;
406
		$pos = -1;
407
		// Remove the string escape for better runtime
408
		$db_string_1 = str_replace('\'\'','',$db_string);
409
		while (true)
410
		{
411
			$pos = strpos($db_string_1, '\'', $pos + 1);
412
			if ($pos === false)
413
				break;
414
			$clean .= substr($db_string_1, $old_pos, $pos - $old_pos);
415
416
			while (true)
417
			{
418
				$pos1 = strpos($db_string_1, '\'', $pos + 1);
419
				$pos2 = strpos($db_string_1, '\\', $pos + 1);
420
				if ($pos1 === false)
421
					break;
422
				elseif ($pos2 === false || $pos2 > $pos1)
423
				{
424
					$pos = $pos1;
425
					break;
426
				}
427
428
				$pos = $pos2 + 1;
429
			}
430
			$clean .= ' %s ';
431
432
			$old_pos = $pos + 1;
433
		}
434
		$clean .= substr($db_string_1, $old_pos);
435
		$clean = trim(strtolower(preg_replace($allowed_comments_from, $allowed_comments_to, $clean)));
436
437
		// Comments?  We don't use comments in our queries, we leave 'em outside!
438
		if (strpos($clean, '/*') > 2 || strpos($clean, '--') !== false || strpos($clean, ';') !== false)
439
			$fail = true;
440
		// Trying to change passwords, slow us down, or something?
441
		elseif (strpos($clean, 'sleep') !== false && preg_match('~(^|[^a-z])sleep($|[^[_a-z])~s', $clean) != 0)
442
			$fail = true;
443
		elseif (strpos($clean, 'benchmark') !== false && preg_match('~(^|[^a-z])benchmark($|[^[a-z])~s', $clean) != 0)
444
			$fail = true;
445
446
		if (!empty($fail) && function_exists('log_error'))
447
			smf_db_error_backtrace('Hacking attempt...', 'Hacking attempt...' . "\n" . $db_string, E_USER_ERROR, __FILE__, __LINE__);
448
	}
449
450
	// Set optimize stuff
451
	if (isset($query_opt[$identifier]))
452
	{
453
		$query_hints = $query_opt[$identifier];
454
		$query_hints_set = '';
455
		if (isset($query_hints['join_collapse_limit']))
456
		{
457
			$query_hints_set .= 'SET LOCAL join_collapse_limit = ' . $query_hints['join_collapse_limit'] . ';';
458
		}
459
		if (isset($query_hints['enable_seqscan']))
460
		{
461
			$query_hints_set .= 'SET LOCAL enable_seqscan = ' . $query_hints['enable_seqscan'] . ';';
462
		}
463
464
		$db_string = $query_hints_set . $db_string;
465
	}
466
467
	// Debugging.
468 View Code Duplication
	if (isset($db_show_debug) && $db_show_debug === true)
469
	{
470
		// Get the file and line number this function was called.
471
		list ($file, $line) = smf_db_error_backtrace('', '', 'return', __FILE__, __LINE__);
472
473
		// Initialize $db_cache if not already initialized.
474
		if (!isset($db_cache))
475
			$db_cache = array();
476
477
		if (!empty($_SESSION['debug_redirect']))
478
		{
479
			$db_cache = array_merge($_SESSION['debug_redirect'], $db_cache);
480
			$db_count = count($db_cache) + 1;
481
			$_SESSION['debug_redirect'] = array();
482
		}
483
484
		// Don't overload it.
485
		$db_cache[$db_count]['q'] = $db_count < 50 ? $db_string : '...';
486
		$db_cache[$db_count]['f'] = $file;
487
		$db_cache[$db_count]['l'] = $line;
488
		$db_cache[$db_count]['s'] = ($st = microtime(true)) - $time_start;
489
	}
490
491
	$db_last_result = @pg_query($connection, $db_string);
492
493 View Code Duplication
	if ($db_last_result === false && empty($db_values['db_error_skip']))
494
		$db_last_result = smf_db_error($db_string, $connection);
495
496
	// Debugging.
497 View Code Duplication
	if (isset($db_show_debug) && $db_show_debug === true)
498
		$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...
499
500
	return $db_last_result;
501
}
502
503
/**
504
 * Returns the amount of affected rows for a query.
505
 *
506
 * @param mixed $result
507
 *
508
 * @return int
509
 *
510
 */
511
function smf_db_affected_rows($result = 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 (L503-508) 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...
512
{
513
	global $db_last_result, $db_replace_result;
514
515
	if ($db_replace_result)
516
		return $db_replace_result;
517
	elseif ($result === null && !$db_last_result)
518
		return 0;
519
520
	return pg_affected_rows($result === null ? $db_last_result : $result);
521
}
522
523
/**
524
 * Gets the ID of the most recently inserted row.
525
 *
526
 * @param string $table The table (only used for Postgres)
527
 * @param string $field = null The specific field (not used here)
0 ignored issues
show
Documentation introduced by
Should the type for parameter $field not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
528
 * @param resource $connection = null The connection (if null, $db_connection is used) (not used here)
0 ignored issues
show
Documentation introduced by
Should the type for parameter $connection not be resource|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
529
 * @return int The ID of the most recently inserted row
530
 */
531
function smf_db_insert_id($table, $field = null, $connection = null)
0 ignored issues
show
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...
Unused Code introduced by
The parameter $connection 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...
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 (L518-524) 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...
532
{
533
	global $smcFunc, $db_prefix;
534
535
	$table = str_replace('{db_prefix}', $db_prefix, $table);
536
537
	// Try get the last ID for the auto increment field.
538
	$request = $smcFunc['db_query']('', 'SELECT CURRVAL(\'' . $table . '_seq\') AS insertID',
539
		array(
540
		)
541
	);
542
	if (!$request)
543
		return false;
544
	list ($lastID) = $smcFunc['db_fetch_row']($request);
545
	$smcFunc['db_free_result']($request);
546
547
	return $lastID;
548
}
549
550
/**
551
 * Do a transaction.
552
 *
553
 * @param string $type The step to perform (i.e. 'begin', 'commit', 'rollback')
554
 * @param resource $connection The connection to use (if null, $db_connection is used)
0 ignored issues
show
Documentation introduced by
Should the type for parameter $connection not be resource|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
555
 * @return bool True if successful, false otherwise
556
 */
557 View Code Duplication
function smf_db_transaction($type = 'commit', $connection = null)
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_transaction() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L533-548) 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...
558
{
559
	global $db_connection;
560
561
	// Decide which connection to use
562
	$connection = $connection === null ? $db_connection : $connection;
563
564
	if ($type == 'begin')
565
		return @pg_query($connection, 'BEGIN');
566
	elseif ($type == 'rollback')
567
		return @pg_query($connection, 'ROLLBACK');
568
	elseif ($type == 'commit')
569
		return @pg_query($connection, 'COMMIT');
570
571
	return false;
572
}
573
574
/**
575
 * Database error!
576
 * Backtrace, log, try to fix.
577
 *
578
 * @param string $db_string The DB string
579
 * @param resource $connection The connection to use (if null, $db_connection is used)
0 ignored issues
show
Documentation introduced by
Should the type for parameter $connection not be object|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
580
 */
581
function smf_db_error($db_string, $connection = null)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
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 (L557-714) 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...
582
{
583
	global $txt, $context, $modSettings;
584
	global $db_connection;
585
	global $db_show_debug;
586
587
	// We'll try recovering the file and line number the original db query was called from.
588
	list ($file, $line) = smf_db_error_backtrace('', '', 'return', __FILE__, __LINE__);
589
590
	// Decide which connection to use
591
	$connection = $connection === null ? $db_connection : $connection;
592
593
	// This is the error message...
594
	$query_error = @pg_last_error($connection);
595
596
	// Log the error.
597
	if (function_exists('log_error'))
598
		log_error($txt['database_error'] . ': ' . $query_error . (!empty($modSettings['enableErrorQueryLogging']) ? "\n\n" . $db_string : ''), 'database', $file, $line);
599
600
	// Nothing's defined yet... just die with it.
601
	if (empty($context) || empty($txt))
602
		die($query_error);
603
604
	// Show an error message, if possible.
605
	$context['error_title'] = $txt['database_error'];
606 View Code Duplication
	if (allowedTo('admin_forum'))
607
		$context['error_message'] = nl2br($query_error) . '<br>' . $txt['file'] . ': ' . $file . '<br>' . $txt['line'] . ': ' . $line;
608
	else
609
		$context['error_message'] = $txt['try_again'];
610
611 View Code Duplication
	if (allowedTo('admin_forum') && isset($db_show_debug) && $db_show_debug === true)
612
	{
613
		$context['error_message'] .= '<br><br>' . nl2br($db_string);
614
	}
615
616
	// It's already been logged... don't log it again.
617
	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...
618
}
619
620
/**
621
 * Inserts data into a table
622
 *
623
 * @param string $method The insert method - can be 'replace', 'ignore' or 'insert'
624
 * @param string $table The table we're inserting the data into
625
 * @param array $columns An array of the columns we're inserting the data into. Should contain 'column' => 'datatype' pairs
626
 * @param array $data The data to insert
627
 * @param array $keys The keys for the table
628
 * @param int returnmode 0 = nothing(default), 1 = last row id, 2 = all rows id as array; every mode runs only with method != 'ignore'
629
 * @param resource $connection The connection to use (if null, $db_connection is used)
0 ignored issues
show
Documentation introduced by
Should the type for parameter $connection not be object|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
630
 * @return mixed value of the first key, behavior based on returnmode. null if no data.
631
 */
632
function smf_db_insert($method = 'replace', $table, $columns, $data, $keys, $returnmode = 0, $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 (L728-869) 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...
633
{
634
	global $smcFunc, $db_connection, $db_prefix;
635
636
	$connection = $connection === null ? $db_connection : $connection;
637
638
	$replace = '';
639
640
	if (empty($data))
641
		return;
642
643
	if (!is_array($data[array_rand($data)]))
644
		$data = array($data);
645
646
	// Replace the prefix holder with the actual prefix.
647
	$table = str_replace('{db_prefix}', $db_prefix, $table);
648
649
	// Sanity check for replace is key part of the columns array
650 View Code Duplication
	if ($method == 'replace' && count(array_intersect_key($columns, array_flip($keys))) !== count($keys))
651
		smf_db_error_backtrace('Primary Key field missing in insert call',
652
				'Change the method of db insert to insert or add the pk field to the columns array', E_USER_ERROR, __FILE__, __LINE__);
653
654
	// PostgreSQL doesn't support replace: we implement a MySQL-compatible behavior instead
655
	if ($method == 'replace' || $method == 'ignore')
656
	{
657
		$key_str = '';
658
		$col_str = '';
659
		$replace_support = $smcFunc['db_native_replace']();
660
661
		$count = 0;
662
		$where = '';
663
		$count_pk = 0;
664
665
		If ($replace_support)
666
		{
667
			foreach ($columns as $columnName => $type)
668
			{
669
				//check pk fiel
670
				IF (in_array($columnName, $keys))
671
				{
672
					$key_str .= ($count_pk > 0 ? ',' : '');
673
					$key_str .= $columnName;
674
					$count_pk++;
675
				}
676
				else if ($method == 'replace') //normal field
677
				{
678
					$col_str .= ($count > 0 ? ',' : '');
679
					$col_str .= $columnName . ' = EXCLUDED.' . $columnName;
680
					$count++;
681
				}
682
			}
683
			if ($method == 'replace')
684
				$replace = ' ON CONFLICT (' . $key_str . ') DO UPDATE SET ' . $col_str;
685
			else
686
				$replace = ' ON CONFLICT (' . $key_str . ') DO NOTHING';
687
		}
688
		else if ($method == 'replace')
689
		{
690
			foreach ($columns as $columnName => $type)
691
			{
692
				// Are we restricting the length?
693
				if (strpos($type, 'string-') !== false)
694
					$actualType = sprintf($columnName . ' = SUBSTRING({string:%1$s}, 1, ' . substr($type, 7) . '), ', $count);
695
				else
696
					$actualType = sprintf($columnName . ' = {%1$s:%2$s}, ', $type, $count);
697
698
				// A key? That's what we were looking for.
699
				if (in_array($columnName, $keys))
700
					$where .= (empty($where) ? '' : ' AND ') . substr($actualType, 0, -2);
701
				$count++;
702
			}
703
704
			// Make it so.
705
			if (!empty($where) && !empty($data))
706
			{
707
				foreach ($data as $k => $entry)
708
				{
709
					$smcFunc['db_query']('', '
710
						DELETE FROM ' . $table .
711
						' WHERE ' . $where,
712
						$entry, $connection
713
					);
714
				}
715
			}
716
		}
717
	}
718
719
	$returning = '';
720
	$with_returning = false;
721
	// lets build the returning string, mysql allow only in normal mode
722 View Code Duplication
	if (!empty($keys) && (count($keys) > 0) && $returnmode > 0)
723
	{
724
		// we only take the first key
725
		$returning = ' RETURNING '.$keys[0];
726
		$with_returning = true;
727
	}
728
729
	if (!empty($data))
730
	{
731
		// Create the mold for a single row insert.
732
		$insertData = '(';
733 View Code Duplication
		foreach ($columns as $columnName => $type)
734
		{
735
			// Are we restricting the length?
736
			if (strpos($type, 'string-') !== false)
737
				$insertData .= sprintf('SUBSTRING({string:%1$s}, 1, ' . substr($type, 7) . '), ', $columnName);
738
			else
739
				$insertData .= sprintf('{%1$s:%2$s}, ', $type, $columnName);
740
		}
741
		$insertData = substr($insertData, 0, -2) . ')';
742
743
		// Create an array consisting of only the columns.
744
		$indexed_columns = array_keys($columns);
745
746
		// Here's where the variables are injected to the query.
747
		$insertRows = array();
748
		foreach ($data as $dataRow)
749
			$insertRows[] = smf_db_quote($insertData, array_combine($indexed_columns, $dataRow), $connection);
750
751
		// Do the insert.
752
		$request = $smcFunc['db_query']('', '
753
			INSERT INTO ' . $table . '("' . implode('", "', $indexed_columns) . '")
754
			VALUES
755
				' . implode(',
756
				', $insertRows).$replace.$returning,
757
			array(
758
				'security_override' => true,
759
				'db_error_skip' => $method == 'ignore' || $table === $db_prefix . 'log_errors',
760
			),
761
			$connection
762
		);
763
764
		if ($with_returning && $request !== false)
765
		{
766
			if ($returnmode === 2)
767
				$return_var = array();
768
769
			while(($row = $smcFunc['db_fetch_row']($request)) && $with_returning)
770
			{
771
				if (is_numeric($row[0])) // try to emulate mysql limitation
772
				{
773
					if ($returnmode === 1)
774
						$return_var = $row[0];
775
					elseif ($returnmode === 2)
776
						$return_var[] = $row[0];
0 ignored issues
show
Bug introduced by
The variable $return_var 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...
777
				}
778
				else
779
				{
780
					$with_returning = false;
781
					trigger_error('trying to returning ID Field which is not a Int field', E_USER_ERROR);
782
				}
783
			}
784
		}
785
	}
786
787
	if ($with_returning && !empty($return_var))
788
		return $return_var;
789
}
790
791
/**
792
 * Dummy function really. Doesn't do anything on PostgreSQL.
793
 *
794
 * @param string $db_name The database name
795
 * @param resource $db_connection The database connection
796
 * @return true Always returns true
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
797
 */
798
function smf_db_select_db($db_name, $db_connection)
0 ignored issues
show
Unused Code introduced by
The parameter $db_name 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 $db_connection 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...
799
{
800
	return true;
801
}
802
803
/**
804
 * Get the current version.
805
 * @return string The client version
806
 */
807
function smf_db_version()
808
{
809
	$version = pg_version();
810
811
	return $version['client'];
812
}
813
814
/**
815
 * This function tries to work out additional error information from a back trace.
816
 *
817
 * @param string $error_message The error message
818
 * @param string $log_message The message to log
819
 * @param string|bool $error_type What type of error this is
820
 * @param string $file The file the error occurred in
0 ignored issues
show
Documentation introduced by
Should the type for parameter $file not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
821
 * @param int $line What line of $file the code which generated the error is on
0 ignored issues
show
Documentation introduced by
Should the type for parameter $line not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
822
 * @return void|array Returns an array with the file and line if $error_type is 'return'
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array|null.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
823
 */
824 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 (L881-921) 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...
825
{
826
	if (empty($log_message))
827
		$log_message = $error_message;
828
829
	foreach (debug_backtrace() as $step)
830
	{
831
		// Found it?
832
		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)
833
		{
834
			$log_message .= '<br>Function: ' . $step['function'];
835
			break;
836
		}
837
838
		if (isset($step['line']))
839
		{
840
			$file = $step['file'];
841
			$line = $step['line'];
842
		}
843
	}
844
845
	// A special case - we want the file and line numbers for debugging.
846
	if ($error_type == 'return')
847
		return array($file, $line);
848
849
	// Is always a critical error.
850
	if (function_exists('log_error'))
851
		log_error($log_message, 'critical', $file, $line);
852
853
	if (function_exists('fatal_error'))
854
	{
855
		fatal_error($error_message, $error_type);
0 ignored issues
show
Bug introduced by
It seems like $error_type defined by parameter $error_type on line 824 can also be of type boolean; however, fatal_error() does only seem to accept string, 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...
856
857
		// Cannot continue...
858
		exit;
859
	}
860
	elseif ($error_type)
861
		trigger_error($error_message . ($line !== null ? '<em>(' . basename($file) . '-' . $line . ')</em>' : ''), $error_type);
862
	else
863
		trigger_error($error_message . ($line !== null ? '<em>(' . basename($file) . '-' . $line . ')</em>' : ''));
864
}
865
866
/**
867
 * Escape the LIKE wildcards so that they match the character and not the wildcard.
868
 *
869
 * @param string $string The string to escape
870
 * @param bool $translate_human_wildcards If true, turns human readable wildcards into SQL wildcards.
871
 * @return string The escaped string
872
 */
873 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 (L930-944) 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...
874
{
875
	$replacements = array(
876
		'%' => '\%',
877
		'_' => '\_',
878
		'\\' => '\\\\',
879
	);
880
881
	if ($translate_human_wildcards)
882
		$replacements += array(
883
			'*' => '%',
884
		);
885
886
	return strtr($string, $replacements);
887
}
888
889
/**
890
 * Fetches all rows from a result as an array
891
 *
892
 * @param resource $request A PostgreSQL result resource
893
 * @return array An array that contains all rows (records) in the result resource
894
 */
895
function smf_db_fetch_all($request)
0 ignored issues
show
Best Practice introduced by
The function smf_db_fetch_all() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L967-979) 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...
896
{
897
	// Return the right row.
898
	$return = @pg_fetch_all($request);
899
	return !empty($return) ? $return : array();
900
}
901
902
/**
903
 * Function to save errors in database in a safe way
904
 *
905
 * @param array with keys in this order id_member, log_time, ip, url, message, session, error_type, file, line
906
 * @return void
907
 */
908
function smf_db_error_insert($error_array)
0 ignored issues
show
Best Practice introduced by
The function smf_db_error_insert() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L987-1010) 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...
909
{
910
	global  $db_prefix, $db_connection;
911
	static $pg_error_data_prep;
912
913
	// without database we can't do anything
914
	if (empty($db_connection))
915
		return;
916
917
	if (empty($pg_error_data_prep))
918
			$pg_error_data_prep = pg_prepare($db_connection, 'smf_log_errors',
919
				'INSERT INTO ' . $db_prefix . 'log_errors(id_member, log_time, ip, url, message, session, error_type, file, line, backtrace)
920
													VALUES(		$1,		$2,		$3, $4, 	$5,		$6,			$7,		$8,	$9, $10)'
921
			);
922
923
	pg_execute($db_connection, 'smf_log_errors', $error_array);
924
}
925
926
/**
927
 * Function which constructs an optimize custom order string
928
 * as an improved alternative to find_in_set()
929
 *
930
 * @param string $field name
931
 * @param array $array_values Field values sequenced in array via order priority. Must cast to int.
932
 * @param boolean $desc default false
933
 * @return string case field when ... then ... end
934
 */
935 View Code Duplication
function smf_db_custom_order($field, $array_values, $desc = false)
0 ignored issues
show
Best Practice introduced by
The function smf_db_custom_order() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L1021-1032) 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...
936
{
937
	$return = 'CASE '. $field . ' ';
938
	$count = count($array_values);
939
	$then = ($desc ? ' THEN -' : ' THEN ');
940
941
	for ($i = 0; $i < $count; $i++)
942
		$return .= 'WHEN ' . (int) $array_values[$i] . $then . $i . ' ';
943
944
	$return .= 'END';
945
	return $return;
946
}
947
948
/**
949
 * Function which return the information if the database supports native replace inserts
950
 *
951
 * @return boolean true or false
952
 */
953
function smf_db_native_replace()
0 ignored issues
show
Best Practice introduced by
The function smf_db_native_replace() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L1039-1042) 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...
954
{
955
	global $smcFunc;
956
	static $pg_version;
957
	static $replace_support;
958
959
	if (empty($pg_version))
960
	{
961
		db_extend();
962
		//pg 9.5 got replace support
963
		$pg_version = $smcFunc['db_get_version']();
964
		// if we got a Beta Version
965 View Code Duplication
		if (stripos($pg_version, 'beta') !== false)
966
			$pg_version = substr($pg_version, 0, stripos($pg_version, 'beta')) . '.0';
967
		// or RC
968 View Code Duplication
		if (stripos($pg_version, 'rc') !== false)
969
			$pg_version = substr($pg_version, 0, stripos($pg_version, 'rc')) . '.0';
970
971
		$replace_support = (version_compare($pg_version, '9.5.0', '>=') ? true : false);
972
	}
973
974
	return $replace_support;
975
}
976
977
/**
978
 * Function which return the information if the database supports cte with recursive
979
 *
980
 * @return boolean true or false
981
 */
982
function smf_db_cte_support()
0 ignored issues
show
Best Practice introduced by
The function smf_db_cte_support() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L1049-1067) 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...
983
{
984
	return true;
985
}
986
987
/**
988
 * Function which return the escaped string
989
 * 
990
 * @param string the unescaped text
991
 * @param resource $connection = null The connection to use (null to use $db_connection)
0 ignored issues
show
Documentation introduced by
Should the type for parameter $connection not be resource|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
992
 * @return string escaped string
993
 */
994
function smf_db_escape_string($string, $connection = null)
0 ignored issues
show
Best Practice introduced by
The function smf_db_escape_string() has been defined more than once; this definition is ignored, only the first definition in Sources/Subs-Db-mysql.php (L1076-1081) 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...
995
{
996
	global $db_connection;
997
998
	return pg_escape_string($connection === null ? $db_connection : $connection, $string);
999
}
1000
1001
?>