Issues (4714)

Security Analysis    not enabled

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.

src/Intraface/User.php (25 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
 * User and rights management
4
 *
5
 * NOTICE:
6
 * Keep in mind the relation between User.php, UserAdministration.php and
7
 * UserMaintenance.php
8
 *
9
 * User.php is ONLY for the function that the normal user is allowed to. That
10
 * means NOT create other users. The user should not be allowed to change is
11
 * own rights.
12
 *
13
 * UserAdministration.php is for the administrator of the intranet. Can create
14
 * new user. Administrator is not allowed to disable a User, as it will affect
15
 * all intranets.
16
 *
17
 * UserMaintenance.php is for overall maintenance team. Should be allowed everthing.
18
 *
19
 * @package Intraface
20
 * @author  Sune Jensen <[email protected]>
21
 * @author  Lars Olesen <[email protected]>
22
 * @since   0.1.0
23
 * @version @package-version@
24
 */
25
require_once 'Intraface/functions.php';
26
27
class Intraface_User extends Intraface_Standard implements Intraface_Identity
28
{
29
    /**
30
     * @var db
31
     */
32
    protected $db;
33
34
    /**
35
     * @var integer
36
     */
37
    protected $id;
38
39
    /**
40
     * @var array
41
     */
42
    public $value;
43
44
    /**
45
     * @var integer
46
     */
47
    protected $intranet_id = 0;
48
49
    /**
50
     * @var error
51
     */
52
    public $error;
53
54
    /**
55
     * @var array
56
     */
57
    protected $permissions = array();
58
59
    /**
60
     * @var array
61
     */
62
    protected $modules = array();
63
64
    /**
65
     * @var address
66
     */
67
    private $address;
68
69
    /**
70
     * @var boolean
71
     */
72
    private $permissions_loaded = false;
73
74
    /**
75
     * Constructor
76
     *
77
     * @param integer $id User id
78
     *
79
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
80
     */
81 19
    public function __construct($id = 0)
82
    {
83 19
        $this->id          = $this->value['id'] = intval($id);
84 19
        $this->db          = MDB2::singleton(DB_DSN);
85 19
        $this->error       = $this->getError();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getError() can also be of type object<Intraface_Error>. However, the property $error is declared as type object<Error>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
86
87 19
        if (PEAR::isError($this->db)) {
88
            throw new Exception($this->db->getMessage() . $this->db->getUserInfo());
89
        }
90
91 19
        if ($this->id > 0) {
92 19
            $this->load();
93 19
        }
94 19
    }
95
96 19
    public function getError()
97
    {
98 19
        if ($this->error) {
99
            return $this->error;
100
        }
101 19
        return ($this->error = new Intraface_Error);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Intraface_Error() of type object<Intraface_Error> is incompatible with the declared type object<Error> of property $error.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
102
    }
103
104
    /**
105
     * Load
106
     *
107
     * @return void
108
     */
109 19
    protected function load()
110
    {
111 19
        $result = $this->db->query("SELECT id, email, disabled FROM user WHERE id = " . $this->db->quote($this->id, 'integer'));
112
113 19
        if (PEAR::isError($result)) {
114
            throw new Exception($result->getUserInfo());
115
        }
116 19 View Code Duplication
        if ($result->numRows() == 1) {
117 19
            $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
118 19
            $this->value = $row;
119 19
            return $this->id;
120
        } else {
121
            return ($this->id = 0);
122
        }
123
    }
124
125
    /**
126
     * Gets the address object
127
     *
128
     * @return object
129
     */
130 2
    public function getAddress()
131
    {
132 2
        if (!empty($this->address)) {
133
            return $this->address;
134
        }
135 2
        return ($this->address = Intraface_Address::factory('user', $this->id));
0 ignored issues
show
Documentation Bug introduced by
It seems like \Intraface_Address::factory('user', $this->id) of type object<Intraface_Address> is incompatible with the declared type object<address> of property $address.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
Deprecated Code introduced by
The method Intraface_Address::factory() has been deprecated.

This method has been deprecated.

Loading history...
136
    }
137
138
    /**
139
     * Gets permissions
140
     *
141
     * @return array
142
     */
143 2
    public function getPermissions()
144
    {
145 2
        return $this->permissions;
146
    }
147
148
    /**
149
     * Loads permissions
150
     *
151
     * @param integer $intranet_id
152
     *
153
     * @return boolean
154
     */
155 9
    private function loadPermissions($intranet_id = null)
156
    {
157 9
        if (!$intranet_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $intranet_id of type integer|null is loosely compared to false; 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...
158 2
            $intranet_id = $this->intranet_id;
159 2
        }
160
161 9
        $result = $this->db->query("SELECT intranet_id, module_id
162
            FROM permission
163 9
            WHERE permission.intranet_id = ". $this->db->quote($intranet_id, 'integer')."
164 9
                AND permission.user_id = ". $this->db->quote($this->get('id'), 'integer'));
165
166 9
        if (PEAR::isError($result)) {
167
            throw new Exception($result->getUserInfo());
168
        }
169
170 9
        while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
171 8
            $this->permissions['intranet']['module'][$row['module_id']] = true;
172 8
            $this->permissions['user']['module'][$row['module_id']] = true;
173 8
            $this->permissions['user']['intranet'][$row['intranet_id']] = true;
174 8
        }
175
176 9
        $this->permissions_loaded = true;
177
178 9
        return true;
179
    }
180
181
    /**
182
     * Gets module id from string
183
     *
184
     * @param integer $module
185
     *
186
     * @return integer
187
     */
188 3
    private function getModuleIdFromString($module)
189
    {
190 3 View Code Duplication
        if (empty($this->modules)) {
191 3
            $result = $this->db->query("SELECT id, name FROM module WHERE active = 1");
192 3
            if (PEAR::isError($result)) {
193
                throw new Exception($result->getUserInfo());
194
            }
195
196 3
            while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
197 3
                $this->modules[$row['name']] = $row['id'];
198 3
            }
199 3
        }
200 3 View Code Duplication
        if (!empty($this->modules[$module])) {
201 3
            return $module_id = $this->modules[$module];
0 ignored issues
show
$module_id is not used, you could remove the assignment.

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

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

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

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

Loading history...
202
        } else {
203
            throw new Exception('user says unknown module ' . $module);
204
        }
205
    }
206
207
    /**
208
     * Clears cached permissions
209
     *
210
     * @return void
211
     */
212 1
    public function clearCachedPermission()
213
    {
214 1
        $this->permissions = array();
215 1
        $this->modules = array();
216 1
        $this->permissions_loaded = false;
217 1
    }
218
219
    /**
220
     * Returns whether the permissions has been loaded
221
     *
222
     * @return boolean
223
     */
224 3
    private function permissionsLoaded()
225
    {
226 3
        return $this->permissions_loaded;
227
    }
228
229
    /**
230
     * Returns whether the user has intranetaccess
231
     *
232
     * @param integer $intranet_id
233
     *
234
     * @return boolean
235
     */
236 9
    public function hasIntranetAccess($intranet_id = 0)
237
    {
238 9
        if ($intranet_id == 0) {
239 5
            $intranet_id = $this->intranet_id;
240 5
        }
241
242
        //if (!$this->permissionsLoaded()) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
243 9
            $this->loadPermissions($intranet_id);
244
        //}
245
246 9
        if (!empty($this->permissions['user']['intranet'][$intranet_id])) {
247 8
            return $this->permissions['user']['intranet'][$intranet_id];
248
        }
249
250 2
        return false;
251
    }
252
253
    /**
254
     * Returns whether user has module Access
255
     *
256
     * @param integer $module
257
     * @param integer $intranet_id
258
     *
259
     * @return integer
260
     */
261 3
    public function hasModuleAccess($module, $intranet_id = 0)
262
    {
263 3
        $filename = PATH_INCLUDE_MODULE . $module . '/Main' . ucfirst($module) . '.php';
264 3 View Code Duplication
        if (file_exists($filename)) {
265 3
            require_once $filename;
266 3
            $module_class = 'Main'.ucfirst($module);
267 3
            $module_object = new $module_class;
268 3
            if ($module_object->isShared()) {
269
                return true;
270
            }
271 3
            if ($module_object->isRequired()) {
272
                return true;
273
            }
274 3
        }
275
276 3
        $intranet_id = intval($intranet_id);
277
278 3
        if ($intranet_id == 0) {
279 3
            $intranet_id = $this->intranet_id;
280 3
        }
281
282 3
        if (!$this->permissionsLoaded()) {
283 1
            $this->loadPermissions($intranet_id);
284 1
        }
285
286
        // getting the module
287 3
        if (is_string($module)) {
288 3
            $module_id = $this->getModuleIdFromString($module);
289 3
        } else {
290
            $module_id = intval($module);
291
        }
292
293 3
        if (!empty($this->permissions) and is_array($this->permissions)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
294 3
            if (empty($this->permissions['intranet']['module'][$module_id]) or $this->permissions['intranet']['module'][$module_id] !== true) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
295 2
                return false;
296 2 View Code Duplication
            } elseif (empty($this->permissions['user']['module'][$module_id]) or $this->permissions['user']['module'][$module_id] !== true) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
297
                return false;
298
            } else {
299 2
                return true;
300
            }
301
        }
302 1
        return false;
303
    }
304
305
    /**
306
     * Returns whether user has subaccess
307
     *
308
     * @param integer $module
309
     * @param integer $sub_access
310
     * @param integer intranet_id (n�r den skal tilg�s fra intranetmaintenance (til hvad?)
311
     *
312
     * @return boolean
313
     */
314 1
    public function hasSubAccess($module, $sub_access, $intranet_id = 0)
315
    {
316 1
        settype($intranet_id, "integer");
317 1
        if ($intranet_id == 0) {
318 1
            $intranet_id = $this->intranet_id;
319 1
        }
320
321 1
        if (is_string($module)) {
322
            $module_id = $this->getModuleIdFromString($module);
323
        } else {
324 1
            $module_id = intval($module);
325
        }
326
327 1
        if (is_string($sub_access)) {
328
            $result = $this->db->query("SELECT id FROM module_sub_access WHERE module_id = ".$module_id." AND name = \"".$sub_access."\"");
329
            if (PEAR::isError($result)) {
330
                throw new Exception($result->getUserInfo());
331
            }
332
            if ($row = $result->fetchRow()) {
333
                $sub_access_id = $row['id'];
334
            } else {
335
                throw new Exception("user says unknown subaccess");
336
            }
337
        } else {
338 1
            $sub_access_id = intval($sub_access);
339
        }
340
341
        // If the permissions are not loaded, we will do that.
342 1
        if (empty($this->permissions['intranet']['module'])) {
343
            // Vi tjekker om intranettet har adgang til modullet.
344
            // er den ikke un�dvendig - det kan vi vel lave i den n�ste
345
            // sql-s�tning?
346 1
            $result = $this->db->query("SELECT module.id
347
                FROM permission
348
                INNER JOIN module
349
                    ON permission.module_id = module.id
350 1
                WHERE permission.intranet_id = ".$intranet_id."
351 1
                    AND permission.user_id = 0");
352 1
            if (PEAR::isError($result)) {
353
                throw new Exception($result->getUserInfo());
354
            }
355 1
            while ($row = $result->fetchRow()) {
356
                $this->permissions['intranet']['module'][$row['id']];
357
            }
358 1
        }
359
360
        // first we check whether the use has access to the module.
361 1 View Code Duplication
        if (empty($this->permissions['intranet']['module'][$module_id]) or $this->permissions['intranet']['module'][$module_id] !== true) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
362 1
            return false;
363
        }
364
365
        // then we check whether there is access to the sub access
366 View Code Duplication
        if (!empty($this->permissions['user']['module']['subaccess'][$sub_access_id]) and $this->permissions['user']['module']['subaccess'][$sub_access_id] === true) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
367
            return true;
368
        }
369
370
        // if the check on the array did not go possitive, we make sure it is because they are not loaded.
371
        // @todo: this is probably not a good way to do it.
372
        $sql = "SELECT module_sub_access.id
373
            FROM permission
374
            INNER JOIN module_sub_access
375
                ON permission.module_sub_access_id = module_sub_access.id
376
            INNER JOIN module
377
                ON permission.module_id = module.id
378
            WHERE permission.intranet_id = ".$intranet_id."
379
                AND permission.user_id = ".$this->id."
380
                AND module.id = ".$module_id."
381
                AND module_sub_access.module_id = module.id";
382
383
        $result = $this->db->query($sql);
384
        if (PEAR::isError($result)) {
385
            throw new Exception($result->getUserInfo());
386
        }
387
        while ($row = $result->fetchRow()) {
388
            $this->permissions['user']['module']['subaccess'][$row['id']] = true;
389
        }
390
391 View Code Duplication
        if (!empty($this->permissions['user']['module']['subaccess'][$sub_access_id]) and $this->permissions['user']['module']['subaccess'][$sub_access_id] === true) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
392
            return true;
393
        }
394
395
        return false;
396
    }
397
398
    /**
399
     * Returns the active intranet
400
     *
401
     * @return integer
402
     */
403 2
    public function getActiveIntranetId()
404
    {
405 2
        $result = $this->db->query("SELECT active_intranet_id FROM user WHERE id = ".$this->db->quote($this->id, 'integer'));
406 2
        if (PEAR::isError($result)) {
407
            throw new Exception($result->getUserInfo());
408
        }
409
410 2
        if ($result->numRows() == 1) {
411 2
            $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
412 2
            if ($this->hasIntranetAccess($row['active_intranet_id']) and $row['active_intranet_id'] != 0) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
413 1
                return $row['active_intranet_id'];
414
            }
415 1
        }
416
417 1
        $result = $this->db->query("SELECT intranet.id
418
            FROM intranet
419
            INNER JOIN permission
420
                ON permission.intranet_id = intranet.id
421 1
            WHERE permission.user_id = " . $this->db->quote($this->id, 'integer'));
422 1
        if (PEAR::isError($result)) {
423
            throw new Exception($result->getUserInfo());
424
        }
425 1
        if ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
426 1
            return $row['id'];
427
        } else {
428
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Intraface_User::getActiveIntranetId of type integer.

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...
429
        }
430
    }
431
432
    function getActiveIntranet()
433
    {
434
        return new Intraface_Intranet($this->getActiveIntranetId());
435
    }
436
437
    function getSetting()
438
    {
439
        return new Intraface_Setting($this->getActiveIntranet()->getId(), $this->getId());
440
    }
441
442
    /**
443
     * Sets intranet_id
444
     *
445
     * @todo what is this used for?
446
     *
447
     * @return boolean
448
     */
449 4
    public function setIntranetId($id)
450
    {
451 4
        $this->intranet_id = intval($id);
452 4
        if ($this->id == 0 || $this->hasIntranetAccess()) {
453 4
            $this->load();
454 4
            return true;
455
        }
456
        throw new Exception('you do not have access to this intranet');
457
    }
458
459
    /**
460
     * Sets active intranet_id
461
     *
462
     * @return boolean
463
     */
464 2
    public function setActiveIntranetId($id)
465
    {
466 2
        $id = intval($id);
467 2
        if ($this->hasIntranetAccess($id)) {
468 2
            $this->db->exec("UPDATE user SET active_intranet_id = ". $this->db->quote($id, 'integer')." WHERE id = ". $this->db->quote($this->get('id'), 'integer'));
469 2
            return $id;
470
        }
471
        return false;
472
    }
473
474
    ///////////////////////////////////////////////////////////////////////////////
475
476
    /**
477
     * Gets a list with the users intranets
478
     *
479
     * @return array
480
     */
481 19
    public function getIntranetList()
482
    {
483
        // Skal denne funktion v�re her? M�ske den istedet skulle v�re i intranet.
484 19
        $result = $this->db->query("SELECT DISTINCT(intranet.id), intranet.name FROM intranet
485
            INNER JOIN permission
486
                ON permission.intranet_id = intranet.id
487
            WHERE permission.user_id = ".$this->id);
488
489
        if (PEAR::isError($result)) {
490
            throw new Exception($result->getUserInfo());
491 19
        }
492
        return $result->fetchAll();
493
    }
494
495
    /**
496
     * Validates user info
497
     *
498
     * NOTICE: As it is created now, $input has to be injected by reference,
499
     * because of the little hack with disabled.
500
     *
501
     * @param array $input
502
     *
503
     * @return boolean
504
     */
505 17
    protected function validate(&$input)
506
    {
507 17
        $input = safeToDb($input);
508 17
        $validator = new Intraface_Validator($this->error);
509
510 17
        $validator->isEmail($input["email"], "Ugyldig E-mail");
511 17
        $result = $this->db->query("SELECT id FROM user WHERE email = \"".$input["email"]."\" AND id != ".$this->id);
512 17
        if (PEAR::isError($result)) {
513
            throw new Exception($result->getUserInfo());
514
        }
515 17
        if ($result->numRows() > 0) {
516
            $this->error->set("E-mail-adressen er allerede benyttet");
0 ignored issues
show
The method set() does not seem to exist on object<Error>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
517
        }
518
519 17
        if (isset($input["disabled"])) {
520 17
            $input["disabled"] = 1;
521 17
        } else {
522
            $input["disabled"] = 0;
523
        }
524 17
    }
525
526
    /**
527
     * Updates the user
528
     *
529
     * @param array $input Data to update
530
     *
531
     * @return integer
532
     */
533
    public function update($input)
534
    {
535
        $this->validate($input);
536
537
        $sql = "email = \"".$input["email"]."\",
538
            disabled = ".$input["disabled"]."";
539
540
        if ($this->error->isError()) {
0 ignored issues
show
The method isError() does not seem to exist on object<Error>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
541
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Intraface_User::update of type integer.

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...
542
        }
543
544
        if ($this->id) {
545
            $this->db->exec("UPDATE user SET ".$sql." WHERE id = ".$this->id);
546
            $this->load();
547
            return $this->id;
548
        } else {
549
            throw new Exception("An id is needed to update user details in User->Update()");
550
        }
551
552
        return true;
0 ignored issues
show
return true; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
553
    }
554
555
    function generateNewPassword($email)
556
    {
557
        if (!Validate::email($email)) {
558
            return false;
559
        }
560
        $db = MDB2::singleton(DB_DSN);
561
        $result = $db->query("SELECT id FROM user WHERE email = '".$email."'");
562
        if (PEAR::isError($result)) {
563
            throw new Exception($result->getUserInfo());
564
        }
565
        if ($result->numRows() != 1) {
566
            return false;
567
        }
568
        $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
569
        $new_password = Intraface_Kernel::randomKey(8);
570
571
        $db->exec("UPDATE user SET password = '".md5($new_password)."' WHERE id =" . $row['id']);
572
573
        return $new_password;
574
    }
575
576 2
    public function updatePassword($old_password, $new_password, $repeat_password)
577
    {
578 2
        if ($this->id == 0) {
579
            return false;
580
        }
581
582 2
        $result = $this->db->query("SELECT * FROM user WHERE password = '".safeToDb(md5($old_password))."' AND id = " . $this->get('id'));
583 2
        if ($result->numRows() < 1) {
584
            $this->error->set('error in old password');
0 ignored issues
show
The method set() does not seem to exist on object<Error>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
585
        }
586
587 2
        $validator = new Intraface_Validator($this->error);
588 2
        $validator->isPassword($new_password, 6, 16, "error in new password");
589
590 2
        if ($new_password != $repeat_password) {
591 1
            $this->error->set('error in password');
0 ignored issues
show
The method set() does not seem to exist on object<Error>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
592 1
        }
593
594 2
        if ($this->error->isError()) {
0 ignored issues
show
The method isError() does not seem to exist on object<Error>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
595 1
            return false;
596
        }
597
598 1
        $this->db->query("UPDATE user SET password = '".safeToDb(md5($new_password))."' WHERE id = " . $this->get('id'));
599
600 1
        return true;
601
    }
602
603
    /**
604
     * TODO M�ske kan det g�res enklere, s� der ikke skal bruges s� mange tabeller
605
     */
606 View Code Duplication
    public function getList()
0 ignored issues
show
This method 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...
607
    {
608
        $i = 0;
0 ignored issues
show
$i is not used, you could remove the assignment.

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

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

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

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

Loading history...
609
        $result = $this->db->query("SELECT DISTINCT user.id, user.email, address.name
610
            FROM user
611
            INNER JOIN permission ON permission.user_id = user.id
612
            LEFT JOIN address ON user.id = address.belong_to_id AND address.type = 2
613
            WHERE (address.active = 1 OR address.type IS NULL) AND permission.intranet_id = ".$this->intranet_id."
614
            ORDER BY address.name");
615
616
        if (PEAR::isError($result)) {
617
            throw new Exception($result->getUserInfo());
618
        }
619
        return $result->fetchAll();
620
    }
621
622 1
    public function isFilledIn()
623
    {
624 1
        if ($this->getAddress()->get('phone')) {
625
            return true;
626
        }
627 1
        return false;
628
    }
629
630 2
    public function getId()
631
    {
632 2
        return $this->id;
633
    }
634
635
    function getLanguage()
636
    {
637
        return $this->getSetting()->get('user', 'language');
638
    }
639
}
640