Issues (2473)

Branch: master

Security Analysis    no vulnerabilities found

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

engine/lib/metastrings.php (10 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Elgg metastrngs
4
 * Functions to manage object metastrings.
5
 *
6
 * @package Elgg.Core
7
 * @subpackage DataModel.MetaStrings
8
 */
9
10
/**
11
 * Gets the metastring identifier for a value.
12
 *
13
 * Elgg normalizes the names and values of annotations and metadata. This function
14
 * provides the identifier used as the index in the metastrings table. Plugin
15
 * developers should only use this if denormalizing names/values for performance
16
 * reasons (to avoid multiple joins on the metastrings table).
17
 *
18
 * @param string $string         The value
19
 * @param bool   $case_sensitive Should the retrieval be case sensitive?
20
 *                               If not, there may be more than one result
21
 *
22
 * @return int|array metastring id or array of ids
23
 * @since 1.9.0
24
 */
25
function elgg_get_metastring_id($string, $case_sensitive = true) {
26
	return _elgg_services()->metastringsTable->getId($string, $case_sensitive);
27
}
28
29
/**
30
 * Add a metastring.
31
 *
32
 * @warning You should not call this directly. Use elgg_get_metastring_id().
33
 *
34
 * @param string $string The value to be normalized
35
 * @return int The identifier for this string
36
 */
37
function _elgg_add_metastring($string) {
38
	return _elgg_services()->metastringsTable->add($string);
39
}
40
41
/**
42
 * Returns an array of either \ElggAnnotation or \ElggMetadata objects.
43
 * Accepts all elgg_get_entities() options for entity restraints.
44
 *
45
 * @see elgg_get_entities
46
 *
47
 * @param array $options Array in format:
48
 *
49
 * 	metastring_names              => null|ARR metastring names
50
 *
51
 * 	metastring_values             => null|ARR metastring values
52
 *
53
 * 	metastring_ids                => null|ARR metastring ids
54
 *
55
 * 	metastring_case_sensitive     => BOOL     Overall Case sensitive
56
 *
57
 *  metastring_owner_guids        => null|ARR Guids for metadata owners
58
 *
59
 *  metastring_created_time_lower => INT      Lower limit for created time.
60
 *
61
 *  metastring_created_time_upper => INT      Upper limit for created time.
62
 *
63
 *  metastring_calculation        => STR      Perform the MySQL function on the metastring values
64
 *                                            returned.
65
 *                                            This differs from egef_annotation_calculation in that
66
 *                                            it returns only the calculation of all annotation values.
67
 *                                            You can sum, avg, count, etc. egef_annotation_calculation()
68
 *                                            returns \ElggEntities ordered by a calculation on their
69
 *                                            annotation values.
70
 *
71
 *  metastring_type               => STR      metadata or annotation(s)
72
 *
73
 * @return \ElggExtender[]|int An array or count of metastring based objects
74
 * @access private
75
 */
76
function _elgg_get_metastring_based_objects($options) {
77
	$options = _elgg_normalize_metastrings_options($options);
78
79
	switch ($options['metastring_type']) {
80
		case 'metadata':
81
			$type = 'metadata';
82
			$callback = 'row_to_elggmetadata';
83
			break;
84
85
		case 'annotations':
86
		case 'annotation':
87
			$type = 'annotations';
88
			$callback = 'row_to_elggannotation';
89
			break;
90
91
		default:
92
			return false;
93
	}
94
95
	$defaults = array(
96
		// entities
97
		'types' => ELGG_ENTITIES_ANY_VALUE,
98
		'subtypes' => ELGG_ENTITIES_ANY_VALUE,
99
		'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE,
100
101
		'guids' => ELGG_ENTITIES_ANY_VALUE,
102
		'owner_guids' => ELGG_ENTITIES_ANY_VALUE,
103
		'container_guids' => ELGG_ENTITIES_ANY_VALUE,
104
		'site_guids' => get_config('site_guid'),
105
106
		'modified_time_lower' => ELGG_ENTITIES_ANY_VALUE,
107
		'modified_time_upper' => ELGG_ENTITIES_ANY_VALUE,
108
		'created_time_lower' => ELGG_ENTITIES_ANY_VALUE,
109
		'created_time_upper' => ELGG_ENTITIES_ANY_VALUE,
110
111
		// options are normalized to the plural in case we ever add support for them.
112
		'metastring_names' => ELGG_ENTITIES_ANY_VALUE,
113
		'metastring_values' => ELGG_ENTITIES_ANY_VALUE,
114
		//'metastring_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE,
115
		//'metastring_name_value_pairs_operator' => 'AND',
116
117
		'metastring_case_sensitive' => true,
118
		//'order_by_metastring' => array(),
119
		'metastring_calculation' => ELGG_ENTITIES_NO_VALUE,
120
121
		'metastring_created_time_lower' => ELGG_ENTITIES_ANY_VALUE,
122
		'metastring_created_time_upper' => ELGG_ENTITIES_ANY_VALUE,
123
124
		'metastring_owner_guids' => ELGG_ENTITIES_ANY_VALUE,
125
126
		'metastring_ids' => ELGG_ENTITIES_ANY_VALUE,
127
128
		// sql
129
		'order_by' => 'n_table.time_created ASC, n_table.id ASC',
130
		'limit' => elgg_get_config('default_limit'),
131
		'offset' => 0,
132
		'count' => false,
133
		'selects' => array(),
134
		'wheres' => array(),
135
		'joins' => array(),
136
137
		'distinct' => true,
138
		'preload_owners' => false,
139
		'callback' => $callback,
140
	);
141
142
	// @todo Ignore site_guid right now because of #2910
143
	$options['site_guid'] = ELGG_ENTITIES_ANY_VALUE;
144
145
	$options = array_merge($defaults, $options);
146
147
	// can't use helper function with type_subtype_pair because
148
	// it's already an array...just need to merge it
149 View Code Duplication
	if (isset($options['type_subtype_pair'])) {
150
		if (isset($options['type_subtype_pairs'])) {
151
			$options['type_subtype_pairs'] = array_merge($options['type_subtype_pairs'],
152
				$options['type_subtype_pair']);
153
		} else {
154
			$options['type_subtype_pairs'] = $options['type_subtype_pair'];
155
		}
156
	}
157
158
	$singulars = array(
159
		'type', 'subtype', 'type_subtype_pair',
160
		'guid', 'owner_guid', 'container_guid', 'site_guid',
161
		'metastring_name', 'metastring_value',
162
		'metastring_owner_guid', 'metastring_id',
163
		'select', 'where', 'join'
164
	);
165
166
	$options = _elgg_normalize_plural_options_array($options, $singulars);
167
168
	if (!$options) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $options of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
169
		return false;
170
	}
171
172
	$db_prefix = elgg_get_config('dbprefix');
173
174
	// evaluate where clauses
175
	if (!is_array($options['wheres'])) {
176
		$options['wheres'] = array($options['wheres']);
177
	}
178
179
	$wheres = $options['wheres'];
180
181
	// entities
182
	$wheres[] = _elgg_get_entity_type_subtype_where_sql('e', $options['types'],
183
		$options['subtypes'], $options['type_subtype_pairs']);
184
185
	$wheres[] = _elgg_get_guid_based_where_sql('e.guid', $options['guids']);
186
	$wheres[] = _elgg_get_guid_based_where_sql('e.owner_guid', $options['owner_guids']);
187
	$wheres[] = _elgg_get_guid_based_where_sql('e.container_guid', $options['container_guids']);
188
	$wheres[] = _elgg_get_guid_based_where_sql('e.site_guid', $options['site_guids']);
189
190
	$wheres[] = _elgg_get_entity_time_where_sql('e', $options['created_time_upper'],
191
		$options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']);
192
193
194
	$wheres[] = _elgg_get_entity_time_where_sql('n_table', $options['metastring_created_time_upper'],
195
		$options['metastring_created_time_lower'], null, null);
196
197
	$wheres[] = _elgg_get_guid_based_where_sql('n_table.owner_guid',
198
		$options['metastring_owner_guids']);
199
200
	// see if any functions failed
201
	// remove empty strings on successful functions
202 View Code Duplication
	foreach ($wheres as $i => $where) {
203
		if ($where === false) {
204
			return false;
205
		} elseif (empty($where)) {
206
			unset($wheres[$i]);
207
		}
208
	}
209
210
	// remove identical where clauses
211
	$wheres = array_unique($wheres);
212
213
	// evaluate join clauses
214
	if (!is_array($options['joins'])) {
215
		$options['joins'] = array($options['joins']);
216
	}
217
218
	$joins = array();
219
	$joins[] = "JOIN {$db_prefix}entities e ON n_table.entity_guid = e.guid";
220
221
	// evaluate selects
222
	if (!is_array($options['selects'])) {
223
		$options['selects'] = array($options['selects']);
224
	}
225
226
	$selects = $options['selects'];
227
228
	// For performance reasons we don't want the joins required for metadata / annotations
229
	// unless we're going through one of their callbacks.
230
	// this means we expect the functions passing different callbacks to pass their required joins.
231
	// If we're doing a calculation
232
	$custom_callback = ($options['callback'] == 'row_to_elggmetadata'
233
						|| $options['callback'] == 'row_to_elggannotation');
234
	$is_calculation = $options['metastring_calculation'] ? true : false;
235
236
	if ($custom_callback || $is_calculation) {
237
		$joins[] = "JOIN {$db_prefix}metastrings n on n_table.name_id = n.id";
238
		$joins[] = "JOIN {$db_prefix}metastrings v on n_table.value_id = v.id";
239
240
		$selects[] = 'n.string as name';
241
		$selects[] = 'v.string as value';
242
	}
243
244
	// add optional joins
245
	$joins = array_merge($joins, $options['joins']);
246
247
	// metastrings
248
	$metastring_clauses = _elgg_get_metastring_sql('n_table', $options['metastring_names'],
249
		$options['metastring_values'], null, $options['metastring_ids'],
250
		$options['metastring_case_sensitive']);
251
252
	if ($metastring_clauses) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $metastring_clauses of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
253
		$wheres = array_merge($wheres, $metastring_clauses['wheres']);
254
		$joins = array_merge($joins, $metastring_clauses['joins']);
255
	} else {
256
		$wheres[] = _elgg_get_access_where_sql(array(
257
			'table_alias' => 'n_table',
258
			'guid_column' => 'entity_guid',
259
		));
260
	}
261
262
	$distinct = $options['distinct'] ? "DISTINCT " : "";
263
264
	if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE && !$options['count']) {
265
		$selects = array_unique($selects);
266
		// evalutate selects
267
		$select_str = '';
268
		if ($selects) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $selects of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
269
			foreach ($selects as $select) {
270
				$select_str .= ", $select";
271
			}
272
		}
273
274
		$query = "SELECT $distinct n_table.*{$select_str} FROM {$db_prefix}$type n_table";
275
	} elseif ($options['count']) {
276
		// count is over the entities
277
		$query = "SELECT count($distinct e.guid) as calculation FROM {$db_prefix}$type n_table";
278
	} else {
279
		$query = "SELECT {$options['metastring_calculation']}(v.string) as calculation FROM {$db_prefix}$type n_table";
280
	}
281
282 View Code Duplication
	foreach ($joins as $i => $join) {
283
		if ($join === false) {
284
			return false;
285
		} elseif (empty($join)) {
286
			unset($joins[$i]);
287
		}
288
	}
289
290
	// remove identical join clauses
291
	$joins = array_unique($joins);
292
293
	// add joins
294
	foreach ($joins as $j) {
295
		$query .= " $j ";
296
	}
297
298
	// add wheres
299
	$query .= ' WHERE ';
300
301
	foreach ($wheres as $w) {
302
		$query .= " $w AND ";
303
	}
304
305
	// Add access controls
306
	$query .= _elgg_get_access_where_sql(array('table_alias' => 'e'));
307
308
	// reverse order by
309
	if (isset($options['reverse_order_by']) && $options['reverse_order_by']) {
310
		$options['order_by'] = _elgg_sql_reverse_order_by_clause($options['order_by']);
311
	}
312
313
	if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE && !$options['count']) {
314
		if (isset($options['group_by'])) {
315
			$options['group_by'] = sanitise_string($options['group_by']);
316
			$query .= " GROUP BY {$options['group_by']}";
317
		}
318
319 View Code Duplication
		if (isset($options['order_by']) && $options['order_by']) {
320
			$options['order_by'] = sanitise_string($options['order_by']);
321
			$query .= " ORDER BY {$options['order_by']}, n_table.id";
322
		}
323
324 View Code Duplication
		if ($options['limit']) {
325
			$limit = sanitise_int($options['limit']);
326
			$offset = sanitise_int($options['offset'], false);
327
			$query .= " LIMIT $offset, $limit";
328
		}
329
330
		$dt = get_data($query, $options['callback']);
331
332
		if ($options['preload_owners'] && is_array($dt) && count($dt) > 1) {
333
			_elgg_services()->entityPreloader->preload($dt, ['owner_guid']);
334
		}
335
336
		return $dt;
337
	} else {
338
		$result = get_data_row($query);
339
		return $result->calculation;
340
	}
341
}
342
343
/**
344
 * Returns an array of joins and wheres for use in metastrings.
345
 *
346
 * @note The $pairs is reserved for name/value pairs if we want to implement those.
347
 *
348
 * @param string $table          The annotation or metadata table name or alias
349
 * @param array  $names          An array of names
350
 * @param array  $values         An array of values
351
 * @param array  $pairs          Name / value pairs. Not currently used.
352
 * @param array  $ids            Metastring IDs
353
 * @param bool   $case_sensitive Should name and values be case sensitive?
354
 *
355
 * @return array
356
 * @access private
357
 */
358
function _elgg_get_metastring_sql($table, $names = null, $values = null,
359
	$pairs = null, $ids = null, $case_sensitive = false) {
360
361
	if ((!$names && $names !== 0)
362
		&& (!$values && $values !== 0)
363
		&& !$ids
364
		&& (!$pairs && $pairs !== 0)) {
365
366
		return array();
367
	}
368
369
	$db_prefix = elgg_get_config('dbprefix');
370
371
	// binary forces byte-to-byte comparision of strings, making
372
	// it case- and diacritical-mark- sensitive.
373
	// only supported on values.
374
	$binary = ($case_sensitive) ? ' BINARY ' : '';
375
376
	$return = array (
377
		'joins' => array (),
378
		'wheres' => array()
379
	);
380
381
	$wheres = array();
382
383
	// get names wheres and joins
384
	$names_where = '';
385 View Code Duplication
	if ($names !== null) {
386
		if (!is_array($names)) {
387
			$names = array($names);
388
		}
389
390
		$sanitised_names = array();
391
		foreach ($names as $name) {
392
			// normalise to 0.
393
			if (!$name) {
394
				$name = '0';
395
			}
396
			$sanitised_names[] = '\'' . sanitise_string($name) . '\'';
397
		}
398
399
		if ($names_str = implode(',', $sanitised_names)) {
400
			$return['joins'][] = "JOIN {$db_prefix}metastrings msn on $table.name_id = msn.id";
401
			$names_where = "(msn.string IN ($names_str))";
402
		}
403
	}
404
405
	// get values wheres and joins
406
	$values_where = '';
407 View Code Duplication
	if ($values !== null) {
408
		if (!is_array($values)) {
409
			$values = array($values);
410
		}
411
412
		$sanitised_values = array();
413
		foreach ($values as $value) {
414
			// normalize to 0
415
			if (!$value) {
416
				$value = 0;
417
			}
418
			$sanitised_values[] = '\'' . sanitise_string($value) . '\'';
419
		}
420
421
		if ($values_str = implode(',', $sanitised_values)) {
422
			$return['joins'][] = "JOIN {$db_prefix}metastrings msv on $table.value_id = msv.id";
423
			$values_where = "({$binary}msv.string IN ($values_str))";
424
		}
425
	}
426
427
	if ($ids !== null) {
428
		if (!is_array($ids)) {
429
			$ids = array($ids);
430
		}
431
432
		$ids_str = implode(',', $ids);
433
434
		if ($ids_str) {
435
			$wheres[] = "n_table.id IN ($ids_str)";
436
		}
437
	}
438
439 View Code Duplication
	if ($names_where && $values_where) {
440
		$wheres[] = "($names_where AND $values_where)";
441
	} elseif ($names_where) {
442
		$wheres[] = $names_where;
443
	} elseif ($values_where) {
444
		$wheres[] = $values_where;
445
	}
446
447
	$wheres[] = _elgg_get_access_where_sql(array(
448
		'table_alias' => $table,
449
		'guid_column' => 'entity_guid',
450
	));
451
452
	if ($where = implode(' AND ', $wheres)) {
453
		$return['wheres'][] = "($where)";
454
	}
455
456
	return $return;
457
}
458
459
/**
460
 * Normalizes metadata / annotation option names to their corresponding metastrings name.
461
 *
462
 * @param array $options An options array
463
 * @return array
464
 * @access private
465
 */
466
function _elgg_normalize_metastrings_options(array $options = array()) {
467
468
	// support either metastrings_type or metastring_type
469
	// because I've made this mistake many times and hunting it down is a pain...
470
	$type = elgg_extract('metastring_type', $options, null);
471
	$type = elgg_extract('metastrings_type', $options, $type);
472
473
	$options['metastring_type'] = $type;
474
475
	// support annotation_ and annotations_ because they're way too easy to confuse
476
	$prefixes = array('metadata_', 'annotation_', 'annotations_');
477
478
	// map the metadata_* options to metastring_* options
479
	$map = array(
480
		'names'					=>	'metastring_names',
481
		'values'				=>	'metastring_values',
482
		'case_sensitive'		=>	'metastring_case_sensitive',
483
		'owner_guids'			=>	'metastring_owner_guids',
484
		'created_time_lower'	=>	'metastring_created_time_lower',
485
		'created_time_upper'	=>	'metastring_created_time_upper',
486
		'calculation'			=>	'metastring_calculation',
487
		'ids'					=>	'metastring_ids',
488
	);
489
490
	foreach ($prefixes as $prefix) {
491
		$singulars = array("{$prefix}name", "{$prefix}value", "{$prefix}owner_guid", "{$prefix}id");
492
		$options = _elgg_normalize_plural_options_array($options, $singulars);
493
494
		foreach ($map as $specific => $normalized) {
495
			$key = $prefix . $specific;
496
			if (isset($options[$key])) {
497
				$options[$normalized] = $options[$key];
498
			}
499
		}
500
	}
501
502
	return $options;
503
}
504
505
/**
506
 * Enables or disables a metastrings-based object by its id.
507
 *
508
 * @warning To enable disabled metastrings you must first use
509
 * {@link access_show_hidden_entities()}.
510
 *
511
 * @param int    $id      The object's ID
512
 * @param string $enabled Value to set to: yes or no
513
 * @param string $type    Metastring type: metadata or annotation
514
 *
515
 * @return bool
516
 * @throws InvalidParameterException
517
 * @access private
518
 */
519
function _elgg_set_metastring_based_object_enabled_by_id($id, $enabled, $type) {
520
	$id = (int)$id;
521
	$db_prefix = elgg_get_config('dbprefix');
522
523
	$object = _elgg_get_metastring_based_object_from_id($id, $type);
524
525
	switch ($type) {
526
		case 'annotation':
527
		case 'annotations':
528
			$type = 'annotation';
529
			$table = "{$db_prefix}annotations";
530
			break;
531
532
		case 'metadata':
533
			$table = "{$db_prefix}metadata";
534
			break;
535
	}
536
537
	if ($enabled === 'yes' || $enabled === 1 || $enabled === true) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $enabled (string) and 1 (integer) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
538
		$enabled = 'yes';
539
		$event = 'enable';
540
	} elseif ($enabled === 'no' || $enabled === 0 || $enabled === false) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $enabled (string) and 0 (integer) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
541
		$enabled = 'no';
542
		$event = 'disable';
543
	} else {
544
		return false;
545
	}
546
547
	$return = false;
548
549
	if ($object) {
550
		// don't set it if it's already set.
551
		if ($object->enabled == $enabled) {
552
			$return = false;
553
		} elseif ($object->canEdit() && (elgg_trigger_event($event, $type, $object))) {
0 ignored issues
show
$object is of type object<ElggExtender>, but the function expects a string|null.

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...
554
			$return = update_data("UPDATE $table SET enabled = '$enabled' where id = $id");
0 ignored issues
show
The variable $table 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...
555
		}
556
	}
557
558
	return $return;
559
}
560
561
/**
562
 * Runs metastrings-based objects found using $options through $callback
563
 *
564
 * @warning Unlike _elgg_get_metastring_based_objects() this will not accept an
565
 * empty options array!
566
 *
567
 * @warning This returns null on no ops.
568
 *
569
 * @param array  $options    An options array. {@link _elgg_get_metastring_based_objects()}
570
 * @param string $callback   The callback to pass each result through
571
 * @param bool   $inc_offset Increment the offset? Pass false for callbacks that delete / disable
572
 *
573
 * @return bool|null true on success, false on failure, null if no objects are found.
574
 * @access private
575
 */
576
function _elgg_batch_metastring_based_objects(array $options, $callback, $inc_offset = true) {
577
	if (!$options || !is_array($options)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $options of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
578
		return false;
579
	}
580
581
	$batch = new \ElggBatch('_elgg_get_metastring_based_objects', $options, $callback, 50, $inc_offset);
582
	return $batch->callbackResult;
583
}
584
585
/**
586
 * Returns a singular metastring-based object by its ID.
587
 *
588
 * @param int    $id   The metastring-based object's ID
589
 * @param string $type The type: annotation or metadata
590
 * @return \ElggExtender
591
 * @access private
592
 */
593
function _elgg_get_metastring_based_object_from_id($id, $type) {
594
	$id = (int)$id;
595
	if (!$id) {
596
		return false;
597
	}
598
599
	$options = array(
600
		'metastring_type' => $type,
601
		'metastring_id' => $id,
602
	);
603
604
	$obj = _elgg_get_metastring_based_objects($options);
605
606
	if ($obj && count($obj) == 1) {
607
		return $obj[0];
608
	}
609
610
	return false;
611
}
612
613
/**
614
 * Deletes a metastring-based object by its id
615
 *
616
 * @param int    $id   The object's ID
617
 * @param string $type The object's metastring type: annotation or metadata
618
 * @return bool
619
 * @access private
620
 */
621
function _elgg_delete_metastring_based_object_by_id($id, $type) {
622
	$id = (int)$id;
623
	$db_prefix = elgg_get_config('dbprefix');
624
625
	switch ($type) {
626
		case 'annotations':
627
		case 'annotation':
628
			$table = $db_prefix . 'annotations';
629
			$type = 'annotation';
630
			break;
631
632
		case 'metadata':
633
			$table = $db_prefix . 'metadata';
634
			$type = 'metadata';
635
			break;
636
637
		default:
638
			return false;
639
	}
640
641
	$obj = _elgg_get_metastring_based_object_from_id($id, $type);
642
643
	if ($obj) {
644
		// Tidy up if memcache is enabled.
645
		// @todo only metadata is supported
646
		if ($type == 'metadata') {
647
			static $metabyname_memcache;
648
			if ((!$metabyname_memcache) && (is_memcache_available())) {
649
				$metabyname_memcache = new \ElggMemcache('metabyname_memcache');
650
			}
651
652
			if ($metabyname_memcache) {
653
				// @todo why name_id? is that even populated?
654
				$metabyname_memcache->delete("{$obj->entity_guid}:{$obj->name_id}");
655
			}
656
		}
657
658
		if ($obj->canEdit()) {
659
			// bc code for when we triggered 'delete', 'annotations' #4770
660
			$result = true;
661
			if ($type == "annotation") {
662
				$result = elgg_trigger_event('delete', 'annotations', $obj);
0 ignored issues
show
$obj is of type object<ElggExtender>, but the function expects a string|null.

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...
663
				if ($result === false) {
664
					elgg_deprecated_notice("Use the event 'delete', 'annotation'", 1.9);
665
				}
666
			}
667
668
			if (elgg_trigger_event('delete', $type, $obj) && $result) {
0 ignored issues
show
$obj is of type object<ElggExtender>, but the function expects a string|null.

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...
669
				return (bool)delete_data("DELETE FROM $table WHERE id = $id");
670
			}
671
		}
672
	}
673
674
	return false;
675
}
676
677
/**
678
 * Returns options to pass to elgg_get_entities() for metastrings operations.
679
 *
680
 * @param string $type    Metastring type: annotation or metadata
681
 * @param array  $options Options
682
 *
683
 * @return array
684
 * @access private
685
 */
686
function _elgg_entities_get_metastrings_options($type, $options) {
687
	$valid_types = array('metadata', 'annotation');
688
	if (!in_array($type, $valid_types)) {
689
		return false;
690
	}
691
692
	// the options for annotations are singular (annotation_name) but the table
693
	// is plural (elgg_annotations) so rewrite for the table name.
694
	$n_table = ($type == 'annotation') ? 'annotations' : $type;
695
696
	$singulars = array("{$type}_name", "{$type}_value",
697
		"{$type}_name_value_pair", "{$type}_owner_guid");
698
	$options = _elgg_normalize_plural_options_array($options, $singulars);
699
700
	$clauses = _elgg_get_entity_metadata_where_sql('e', $n_table, $options["{$type}_names"],
701
		$options["{$type}_values"], $options["{$type}_name_value_pairs"],
702
		$options["{$type}_name_value_pairs_operator"], $options["{$type}_case_sensitive"],
703
		$options["order_by_{$type}"], $options["{$type}_owner_guids"]);
704
705
	if ($clauses) {
706
		// merge wheres to pass to elgg_get_entities()
707
		if (isset($options['wheres']) && !is_array($options['wheres'])) {
708
			$options['wheres'] = array($options['wheres']);
709
		} elseif (!isset($options['wheres'])) {
710
			$options['wheres'] = array();
711
		}
712
713
		$options['wheres'] = array_merge($options['wheres'], $clauses['wheres']);
714
715
		// merge joins to pass to elgg_get_entities()
716
		if (isset($options['joins']) && !is_array($options['joins'])) {
717
			$options['joins'] = array($options['joins']);
718
		} elseif (!isset($options['joins'])) {
719
			$options['joins'] = array();
720
		}
721
722
		$options['joins'] = array_merge($options['joins'], $clauses['joins']);
723
724
		if ($clauses['orders']) {
725
			$order_by_metadata = implode(", ", $clauses['orders']);
726 View Code Duplication
			if (isset($options['order_by']) && $options['order_by']) {
727
				$options['order_by'] = "$order_by_metadata, {$options['order_by']}";
728
			} else {
729
				$options['order_by'] = "$order_by_metadata, e.time_created DESC";
730
			}
731
		}
732
	}
733
734
	return $options;
735
}
736
737
/**
738
 * Metastring unit tests
739
 *
740
 * @param string $hook  unit_test
741
 * @param string $type  system
742
 * @param array  $value Array of other tests
743
 *
744
 * @return array
745
 * @access private
746
 */
747
function _elgg_metastrings_test($hook, $type, $value) {
748
	global $CONFIG;
749
	$value[] = $CONFIG->path . 'engine/tests/ElggCoreMetastringsTest.php';
750
	return $value;
751
}
752
753
return function(\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) {
754
	$hooks->registerHandler('unit_test', 'system', '_elgg_metastrings_test');
755
};
756