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/ElggFile.php (2 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
/**
4
 * This class represents a physical file.
5
 *
6
 * Create a new \ElggFile object and specify a filename, and optionally a
7
 * FileStore (if one isn't specified then the default is assumed.)
8
 *
9
 * Open the file using the appropriate mode, and you will be able to
10
 * read and write to the file.
11
 *
12
 * Optionally, you can also call the file's save() method, this will
13
 * turn the file into an entity in the system and permit you to do
14
 * things like attach tags to the file. If you do not save the file, no
15
 * entity is created in the database. This is because there are occasions
16
 * when you may want access to file data on datastores using the \ElggFile
17
 * interface without a need to persist information such as temporary files.
18
 *
19
 * @package    Elgg.Core
20
 * @subpackage DataModel.File
21
 */
22
class ElggFile extends \ElggObject {
23
	/** Filestore */
24
	private $filestore;
25
26
	/** File handle used to identify this file in a filestore. Created by open. */
27
	private $handle;
28
29
	/**
30
	 * Set subtype to 'file'.
31
	 *
32
	 * @return void
33
	 */
34
	protected function initializeAttributes() {
35
		parent::initializeAttributes();
36
37
		$this->attributes['subtype'] = "file";
38
	}
39
40
	/**
41
	 * Loads an \ElggFile entity.
42
	 *
43
	 * @param \stdClass $row Database result or null for new \ElggFile
44
	 */
45
	public function __construct($row = null) {
46
		parent::__construct($row);
47
48
		// Set default filestore
49
		$this->filestore = $this->getFilestore();
50
	}
51
52
	/**
53
	 * Set the filename of this file.
54
	 *
55
	 * @param string $name The filename.
56
	 *
57
	 * @return void
58
	 */
59
	public function setFilename($name) {
60
		$this->filename = $name;
61
	}
62
63
	/**
64
	 * Return the filename.
65
	 *
66
	 * @return string
67
	 */
68
	public function getFilename() {
69
		return $this->filename;
70
	}
71
72
	/**
73
	 * Return the filename of this file as it is/will be stored on the
74
	 * filestore, which may be different to the filename.
75
	 *
76
	 * @return string
77
	 */
78
	public function getFilenameOnFilestore() {
79
		return $this->filestore->getFilenameOnFilestore($this);
80
	}
81
82
	/**
83
	 * Return the size of the filestore associated with this file
84
	 *
85
	 * @param string $prefix         Storage prefix
86
	 * @param int    $container_guid The container GUID of the checked filestore
87
	 *
88
	 * @return int
89
	 */
90
	public function getFilestoreSize($prefix = '', $container_guid = 0) {
91
		if (!$container_guid) {
92
			$container_guid = $this->container_guid;
93
		}
94
		$fs = $this->getFilestore();
95
		// @todo add getSize() to \ElggFilestore
96
		return $fs->getSize($prefix, $container_guid);
97
	}
98
99
	/**
100
	 * Get the mime type of the file.
101
	 *
102
	 * @return string
103
	 */
104
	public function getMimeType() {
105
		if ($this->mimetype) {
106
			return $this->mimetype;
107
		}
108
109
		// @todo Guess mimetype if not here
110
	}
111
112
	/**
113
	 * Set the mime type of the file.
114
	 *
115
	 * @param string $mimetype The mimetype
116
	 *
117
	 * @return bool
118
	 */
119
	public function setMimeType($mimetype) {
120
		return $this->mimetype = $mimetype;
121
	}
122
123
	/**
124
	 * Detects mime types based on filename or actual file.
125
	 *
126
	 * @note This method can be called both dynamically and statically
127
	 *
128
	 * @param mixed $file    The full path of the file to check. For uploaded files, use tmp_name.
129
	 * @param mixed $default A default. Useful to pass what the browser thinks it is.
130
	 * @since 1.7.12
131
	 *
132
	 * @return mixed Detected type on success, false on failure.
133
	 * @todo Move this out into a utility class
134
	 */
135
	public function detectMimeType($file = null, $default = null) {
136
		$class = __CLASS__;
137
		if (!$file && isset($this) && $this instanceof $class) {
138
			$file = $this->getFilenameOnFilestore();
139
		}
140
141
		if (!is_readable($file)) {
142
			return false;
143
		}
144
145
		$mime = $default;
146
147
		// for PHP5 folks.
148
		if (function_exists('finfo_file') && defined('FILEINFO_MIME_TYPE')) {
149
			$resource = finfo_open(FILEINFO_MIME_TYPE);
150
			if ($resource) {
151
				$mime = finfo_file($resource, $file);
152
			}
153
		}
154
155
		// for everyone else.
156
		if (!$mime && function_exists('mime_content_type')) {
157
			$mime = mime_content_type($file);
158
		}
159
160
		$original_filename = isset($this) && $this instanceof $class ? $this->originalfilename : basename($file);
161
		$params = array(
162
			'filename' => $file,
163
			'original_filename' => $original_filename, // @see file upload action
164
			'default' => $default,
165
		);
166
		return _elgg_services()->hooks->trigger('mime_type', 'file', $params, $mime);
167
	}
168
169
	/**
170
	 * Set the optional file description.
171
	 *
172
	 * @param string $description The description.
173
	 *
174
	 * @return bool
175
	 */
176
	public function setDescription($description) {
177
		$this->description = $description;
178
	}
179
180
	/**
181
	 * Open the file with the given mode
182
	 *
183
	 * @param string $mode Either read/write/append
184
	 *
185
	 * @return resource File handler
186
	 *
187
	 * @throws IOException|InvalidParameterException
188
	 */
189
	public function open($mode) {
190
		if (!$this->getFilename()) {
191
			throw new \IOException("You must specify a name before opening a file.");
192
		}
193
194
		// See if file has already been saved
195
		// seek on datastore, parameters and name?
196
197
		// Sanity check
198
		if (
199
			($mode != "read") &&
200
			($mode != "write") &&
201
			($mode != "append")
202
		) {
203
			$msg = "Unrecognized file mode '" . $mode . "'";
204
			throw new \InvalidParameterException($msg);
205
		}
206
207
		// Get the filestore
208
		$fs = $this->getFilestore();
209
210
		// Ensure that we save the file details to object store
211
		//$this->save();
212
213
		// Open the file handle
214
		$this->handle = $fs->open($this, $mode);
215
216
		return $this->handle;
217
	}
218
219
	/**
220
	 * Write data.
221
	 *
222
	 * @param string $data The data
223
	 *
224
	 * @return bool
225
	 */
226
	public function write($data) {
227
		$fs = $this->getFilestore();
228
229
		return $fs->write($this->handle, $data);
230
	}
231
232
	/**
233
	 * Read data.
234
	 *
235
	 * @param int $length Amount to read.
236
	 * @param int $offset The offset to start from.
237
	 *
238
	 * @return mixed Data or false
239
	 */
240
	public function read($length, $offset = 0) {
241
		$fs = $this->getFilestore();
242
243
		return $fs->read($this->handle, $length, $offset);
244
	}
245
246
	/**
247
	 * Gets the full contents of this file.
248
	 *
249
	 * @return mixed The file contents.
250
	 */
251
	public function grabFile() {
252
		$fs = $this->getFilestore();
253
		return $fs->grabFile($this);
254
	}
255
256
	/**
257
	 * Close the file and commit changes
258
	 *
259
	 * @return bool
260
	 */
261
	public function close() {
262
		$fs = $this->getFilestore();
263
264
		if ($fs->close($this->handle)) {
265
			$this->handle = null;
266
267
			return true;
268
		}
269
270
		return false;
271
	}
272
273
	/**
274
	 * Delete this file.
275
	 *
276
	 * @return bool
277
	 */
278
	public function delete() {
279
		$fs = $this->getFilestore();
280
		
281
		$result = $fs->delete($this);
282
		
283
		if ($this->getGUID() && $result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getGUID() of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
284
			$result = parent::delete();
285
		}
286
		
287
		return $result;
288
	}
289
290
	/**
291
	 * Seek a position in the file.
292
	 *
293
	 * @param int $position Position in bytes
294
	 *
295
	 * @return bool
296
	 */
297
	public function seek($position) {
298
		$fs = $this->getFilestore();
299
300
		// @todo add seek() to \ElggFilestore
301
		return $fs->seek($this->handle, $position);
302
	}
303
304
	/**
305
	 * Return the current position of the file.
306
	 *
307
	 * @return int The file position
308
	 */
309
	public function tell() {
310
		$fs = $this->getFilestore();
311
312
		return $fs->tell($this->handle);
313
	}
314
315
	/**
316
	 * Return the size of the file in bytes.
317
	 *
318
	 * @return int
319
	 * @since 1.9
320
	 */
321
	public function getSize() {
322
		return $this->filestore->getFileSize($this);
323
	}
324
325
	/**
326
	 * Return the size of the file in bytes.
327
	 *
328
	 * @return int
329
	 * @deprecated 1.8 Use getSize()
330
	 */
331
	public function size() {
332
		elgg_deprecated_notice("Use \ElggFile::getSize() instead of \ElggFile::size()", 1.9);
333
		return $this->getSize();
334
	}
335
336
	/**
337
	 * Return a boolean value whether the file handle is at the end of the file
338
	 *
339
	 * @return bool
340
	 */
341
	public function eof() {
342
		$fs = $this->getFilestore();
343
344
		return $fs->eof($this->handle);
345
	}
346
347
	/**
348
	 * Returns if the file exists
349
	 *
350
	 * @return bool
351
	 */
352
	public function exists() {
353
		$fs = $this->getFilestore();
354
355
		return $fs->exists($this);
356
	}
357
358
	/**
359
	 * Set a filestore.
360
	 *
361
	 * @param \ElggFilestore $filestore The file store.
362
	 *
363
	 * @return void
364
	 */
365
	public function setFilestore(\ElggFilestore $filestore) {
366
		$this->filestore = $filestore;
367
	}
368
369
	/**
370
	 * Return a filestore suitable for saving this file.
371
	 * This filestore is either a pre-registered filestore,
372
	 * a filestore as recorded in metadata or the system default.
373
	 *
374
	 * @return \ElggFilestore
375
	 *
376
	 * @throws ClassNotFoundException
377
	 */
378
	protected function getFilestore() {
379
		// Short circuit if already set.
380
		if ($this->filestore) {
381
			return $this->filestore;
382
		}
383
384
		// ask for entity specific filestore
385
		// saved as filestore::className in metadata.
386
		// need to get all filestore::* metadata because the rest are "parameters" that
387
		// get passed to filestore::setParameters()
388
		if ($this->guid) {
389
			$options = array(
390
				'guid' => $this->guid,
391
				'where' => array("n.string LIKE 'filestore::%'"),
392
			);
393
394
			$mds = elgg_get_metadata($options);
395
396
			$parameters = array();
397
			foreach ($mds as $md) {
398
				list( , $name) = explode("::", $md->name);
399
				if ($name == 'filestore') {
400
					$filestore = $md->value;
401
				}
402
				$parameters[$name] = $md->value;
403
			}
404
		}
405
406
		// need to check if filestore is set because this entity is loaded in save()
407
		// before the filestore metadata is saved.
408
		if (isset($filestore)) {
409
			if (!class_exists($filestore)) {
410
				$msg = "Unable to load filestore class " . $filestore . " for file " . $this->guid;
411
				throw new \ClassNotFoundException($msg);
412
			}
413
414
			$this->filestore = new $filestore();
415
			$this->filestore->setParameters($parameters);
0 ignored issues
show
The variable $parameters 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...
416
			// @todo explain why $parameters will always be set here (PhpStorm complains)
417
		}
418
419
		// this means the entity hasn't been saved so fallback to default
420
		if (!$this->filestore) {
421
			$this->filestore = get_default_filestore();
422
		}
423
424
		return $this->filestore;
425
	}
426
427
	/**
428
	 * Save the file
429
	 *
430
	 * Write the file's data to the filestore and save
431
	 * the corresponding entity.
432
	 *
433
	 * @see \ElggObject::save()
434
	 *
435
	 * @return bool
436
	 */
437
	public function save() {
438
		if (!parent::save()) {
439
			return false;
440
		}
441
442
		// Save datastore metadata
443
		$params = $this->filestore->getParameters();
444
		foreach ($params as $k => $v) {
445
			$this->setMetadata("filestore::$k", $v);
446
		}
447
448
		// Now make a note of the filestore class
449
		$this->setMetadata("filestore::filestore", get_class($this->filestore));
450
451
		return true;
452
	}
453
454
	/**
455
	 * Get property names to serialize.
456
	 *
457
	 * @return string[]
458
	 */
459
	public function __sleep() {
460
		return array_diff(array_keys(get_object_vars($this)), array(
461
			// Don't persist filestore, which contains CONFIG
462
			// https://github.com/Elgg/Elgg/issues/9081#issuecomment-152859856
463
			'filestore',
464
465
			// a resource
466
			'handle',
467
		));
468
	}
469
470
	/**
471
	 * Reestablish filestore property
472
	 *
473
	 * @return void
474
	 * @throws ClassNotFoundException
475
	 */
476
	public function __wakeup() {
477
		$this->getFilestore();
478
	}
479
}
480