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/classes/ElggRelationship.php (9 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
 * Relationship class.
4
 *
5
 * @package    Elgg.Core
6
 * @subpackage Core
7
 * 
8
 * @property int    $id           The unique identifier (read-only)
9
 * @property int    $guid_one     The GUID of the subject of the relationship
10
 * @property string $relationship The type of the relationship (limit of 50 characters long)
11
 * @property int    $guid_two     The GUID of the target of the relationship
12
 * @property int    $time_created A UNIX timestamp of when the relationship was created (read-only, set on first save)
13
 */
14
class ElggRelationship extends \ElggData implements
15
	Importable // deprecated
0 ignored issues
show
Deprecated Code introduced by
The interface Importable has been deprecated with message: 1.9

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

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

Loading history...
16
{
17
	// database column limit
18
	const RELATIONSHIP_LIMIT = 50;
19
20
	/**
21
	 * Create a relationship object
22
	 *
23
	 * @param \stdClass $row Database row or null for new relationship
24
	 * @throws InvalidArgumentException
25
	 */
26
	public function __construct($row = null) {
27
		$this->initializeAttributes();
28
29
		if ($row === null) {
30
			elgg_deprecated_notice('Passing null to constructor is deprecated. Use add_entity_relationship()', 1.9);
31
			return;
32
		}
33
34
		if (!($row instanceof \stdClass)) {
35
			if (!is_numeric($row)) {
36
				throw new \InvalidArgumentException("Constructor accepts only a \stdClass or null.");
37
			}
38
39
			$id = (int)$row;
40
			elgg_deprecated_notice('Passing an ID to constructor is deprecated. Use get_relationship()', 1.9);
41
			$row = _elgg_get_relationship_row($id);
42
			if (!$row) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $row 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...
43
				throw new \InvalidArgumentException("Relationship not found with ID $id");
44
			}
45
		}
46
47
		foreach ((array)$row as $key => $value) {
48
			$this->attributes[$key] = $value;
49
		}
50
51
		$this->attributes['id'] = (int)$this->attributes['id'];
52
	}
53
54
	/**
55
	 * (non-PHPdoc)
56
	 *
57
	 * @see \ElggData::initializeAttributes()
58
	 *
59
	 * @return void
60
	 */
61
	protected function initializeAttributes() {
62
		parent::initializeAttributes();
63
64
		$this->attributes['id'] = null;
65
		$this->attributes['guid_one'] = null;
66
		$this->attributes['relationship'] = null;
67
		$this->attributes['guid_two'] = null;
68
	}
69
70
	/**
71
	 * Set an attribute of the relationship
72
	 *
73
	 * @param string $name  Name
74
	 * @param mixed  $value Value
75
	 * @return void
76
	 */
77 1
	public function __set($name, $value) {
78 1
		$this->attributes[$name] = $value;
79 1
	}
80
81
	/**
82
	 * Class member set overloading
83
	 *
84
	 * @param string $name  Name
85
	 * @param mixed  $value Value
86
	 * @return mixed
87
	 * @deprecated 1.9
88
	 */
89
	public function set($name, $value) {
90
		elgg_deprecated_notice("Use -> instead of set()", 1.9);
91
		$this->__set($name, $value);
92
		return true;
93
	}
94
95
	/**
96
	 * Get an attribute of the relationship
97
	 *
98
	 * @param string $name Name
99
	 * @return mixed
100
	 */
101 2
	public function __get($name) {
102 2
		if (array_key_exists($name, $this->attributes)) {
103 1
			return $this->attributes[$name];
104
		}
105
106 1
		return null;
107
	}
108
	
109
	/**
110
	 * Class member get overloading
111
	 *
112
	 * @param string $name Name
113
	 * @return mixed
114
	 * @deprecated 1.9
115
	 */
116
	public function get($name) {
117
		elgg_deprecated_notice("Use -> instead of get()", 1.9);
118
		return $this->__get($name);
119
	}
120
121
	/**
122
	 * Save the relationship
123
	 *
124
	 * @return int the relationship ID
125
	 * @throws IOException
126
	 */
127
	public function save() {
128
		if ($this->id > 0) {
129
			delete_relationship($this->id);
130
		}
131
132
		$this->id = _elgg_services()->relationshipsTable->add(
133
			$this->guid_one,
134
			$this->relationship,
135
			$this->guid_two,
136
			true
137
		);
138
		if (!$this->id) {
139
			throw new \IOException("Unable to save new " . get_class());
140
		}
141
142
		return $this->id;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->id; of type integer|boolean adds the type integer to the return on line 142 which is incompatible with the return type declared by the abstract method ElggData::save of type boolean.
Loading history...
143
	}
144
145
	/**
146
	 * Delete this relationship from the database.
147
	 *
148
	 * @return bool
149
	 */
150
	public function delete() {
151
		return delete_relationship($this->id);
0 ignored issues
show
It seems like $this->id can also be of type boolean; however, delete_relationship() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug Compatibility introduced by
The expression delete_relationship($this->id); of type integer|false adds the type integer to the return on line 151 which is incompatible with the return type declared by the abstract method ElggData::delete of type boolean.
Loading history...
152
	}
153
154
	/**
155
	 * Get a URL for this relationship.
156
	 *
157
	 * Plugins can register for the 'relationship:url', 'relationship' plugin hook to
158
	 * customize the url for a relationship.
159
	 *
160
	 * @return string
161
	 */
162
	public function getURL() {
163
		$url = '';
164
		// @todo remove when elgg_register_relationship_url_handler() has been removed
165
		if ($this->id) {
166
			global $CONFIG;
167
168
			$subtype = $this->getSubtype();
169
170
			$function = "";
171
			if (isset($CONFIG->relationship_url_handler[$subtype])) {
172
				$function = $CONFIG->relationship_url_handler[$subtype];
173
			}
174
			if (isset($CONFIG->relationship_url_handler['all'])) {
175
				$function = $CONFIG->relationship_url_handler['all'];
176
			}
177
178
			if (is_callable($function)) {
179
				$url = call_user_func($function, $this);
180
			}
181
182
			if ($url) {
183
				$url = elgg_normalize_url($url);
184
			}
185
		}
186
187
		$type = $this->getType();
188
		$params = array('relationship' => $this);
189
		$url = _elgg_services()->hooks->trigger('relationship:url', $type, $params, $url);
190
191
		return elgg_normalize_url($url);
192
	}
193
194
	/**
195
	 * {@inheritdoc}
196
	 */
197
	public function toObject() {
198
		$object = new \stdClass();
199
		$object->id = $this->id;
200
		$object->subject_guid = $this->guid_one;
201
		$object->relationship = $this->relationship;
202
		$object->object_guid = $this->guid_two;
203
		$object->time_created = date('c', $this->getTimeCreated());
204
		$params = array('relationship' => $this);
205
		return _elgg_services()->hooks->trigger('to:object', 'relationship', $params, $object);
206
	}
207
208
	// EXPORTABLE INTERFACE ////////////////////////////////////////////////////////////
209
210
	/**
211
	 * Return an array of fields which can be exported.
212
	 *
213
	 * @return array
214
	 * @deprecated 1.9 Use toObject()
215
	 */
216
	public function getExportableValues() {
217
		elgg_deprecated_notice(__METHOD__ . ' has been deprecated by toObject()', 1.9);
218
		return array(
219
			'id',
220
			'guid_one',
221
			'relationship',
222
			'guid_two'
223
		);
224
	}
225
226
	/**
227
	 * Export this relationship
228
	 *
229
	 * @return array
230
	 * @deprecated 1.9 Use toObject()
231
	 */
232
	public function export() {
233
		elgg_deprecated_notice(__METHOD__ . ' has been deprecated', 1.9);
234
		$uuid = get_uuid_from_object($this);
235
		$relationship = new ODDRelationship(
0 ignored issues
show
Deprecated Code introduced by
The class ODDRelationship has been deprecated with message: 1.9

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

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

Loading history...
236
			guid_to_uuid($this->guid_one),
237
			$this->relationship,
238
			guid_to_uuid($this->guid_two)
239
		);
240
241
		$relationship->setAttribute('uuid', $uuid);
242
243
		return $relationship;
244
	}
245
246
	// IMPORTABLE INTERFACE ////////////////////////////////////////////////////////////
247
248
	/**
249
	 * Import a relationship
250
	 *
251
	 * @param ODD $data ODD data
252
253
	 * @return bool
254
	 * @throws ImportException|InvalidParameterException
255
	 * @deprecated 1.9
256
	 */
257
	public function import(ODD $data) {
258
		elgg_deprecated_notice(__METHOD__ . ' has been deprecated', 1.9);
259
		if (!($data instanceof ODDRelationship)) {
260
			throw new \InvalidParameterException("import() passed an unexpected ODD class");
261
		}
262
263
		$uuid_one = $data->getAttribute('uuid1');
264
		$uuid_two = $data->getAttribute('uuid2');
265
266
		// See if this entity has already been imported, if so then we need to link to it
267
		$entity1 = get_entity_from_uuid($uuid_one);
268
		$entity2 = get_entity_from_uuid($uuid_two);
269
		if (($entity1) && ($entity2)) {
270
			// Set the item ID
271
			$this->attributes['guid_one'] = $entity1->getGUID();
272
			$this->attributes['guid_two'] = $entity2->getGUID();
273
274
			// Map verb to relationship
275
			//$verb = $data->getAttribute('verb');
276
			//$relationship = get_relationship_from_verb($verb);
277
			$relationship = $data->getAttribute('type');
278
279
			if ($relationship) {
280
				$this->attributes['relationship'] = $relationship;
281
				// save
282
				$result = $this->save();
283
				if (!$result) {
284
					throw new \ImportException("There was a problem saving " . get_class());
0 ignored issues
show
Deprecated Code introduced by
The class ImportException has been deprecated with message: 1.9

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

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

Loading history...
285
				}
286
287
				return true;
288
			}
289
		}
290
291
		return false;
292
	}
293
294
	// SYSTEM LOG INTERFACE ////////////////////////////////////////////////////////////
295
296
	/**
297
	 * Return an identification for the object for storage in the system log.
298
	 * This id must be an integer.
299
	 *
300
	 * @return int
301
	 */
302
	public function getSystemLogID() {
303
		return $this->id;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->id; of type integer|boolean adds the type boolean to the return on line 303 which is incompatible with the return type declared by the interface Loggable::getSystemLogID of type integer.
Loading history...
304
	}
305
306
	/**
307
	 * For a given ID, return the object associated with it.
308
	 * This is used by the river functionality primarily.
309
	 * This is useful for checking access permissions etc on objects.
310
	 *
311
	 * @param int $id ID
312
	 *
313
	 * @return \ElggRelationship
314
	 */
315
	public function getObjectFromID($id) {
316
		return get_relationship($id);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return get_relationship($id); (false|ElggRelationship) is incompatible with the return type declared by the interface Loggable::getObjectFromID of type ElggEntity.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
317
	}
318
319
	/**
320
	 * Return a type of the object - eg. object, group, user, relationship, metadata, annotation etc
321
	 *
322
	 * @return string 'relationship'
323
	 */
324
	public function getType() {
325
		return 'relationship';
326
	}
327
328
	/**
329
	 * Return a subtype. For metadata & annotations this is the 'name' and for relationship this
330
	 * is the relationship type.
331
	 *
332
	 * @return string
333
	 */
334
	public function getSubtype() {
335
		return $this->relationship;
336
	}
337
}
338