Completed
Push — master ( 23153f...eb881d )
by Angus
03:14
created

Ion_auth_model::recheck_session()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 39
Code Lines 21

Duplication

Lines 8
Ratio 20.51 %

Importance

Changes 0
Metric Value
cc 6
eloc 21
nc 10
nop 0
dl 8
loc 39
rs 8.439
c 0
b 0
f 0
1
<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
2
/**
3
* Name:  Ion Auth Model
4
*
5
* Author:  Ben Edmunds
6
* 		   [email protected]
7
*	  	   @benedmunds
8
*
9
* Added Awesomeness: Phil Sturgeon
10
*
11
* Location: http://github.com/benedmunds/CodeIgniter-Ion-Auth
12
*
13
* Created:  10.01.2009
14
*
15
* Description:  Modified auth system based on redux_auth with extensive customization.  This is basically what Redux Auth 2 should be.
16
* Original Author name has been kept but that does not mean that the method has not been modified.
17
*
18
* Requirements: PHP5 or above
19
*
20
*/
21
22
class Ion_auth_model extends CI_Model
23
{
24
	/**
25
	 * Holds an array of tables used
26
	 *
27
	 * @var array
28
	 **/
29
	public $tables = array();
30
31
	/**
32
	 * activation code
33
	 *
34
	 * @var string
35
	 **/
36
	public $activation_code;
37
38
	/**
39
	 * forgotten password key
40
	 *
41
	 * @var string
42
	 **/
43
	public $forgotten_password_code;
44
45
	/**
46
	 * new password
47
	 *
48
	 * @var string
49
	 **/
50
	public $new_password;
51
52
	/**
53
	 * Identity
54
	 *
55
	 * @var string
56
	 **/
57
	public $identity;
58
59
	/**
60
	 * Where
61
	 *
62
	 * @var array
63
	 **/
64
	public $_ion_where = array();
65
66
	/**
67
	 * Select
68
	 *
69
	 * @var array
70
	 **/
71
	public $_ion_select = array();
72
73
	/**
74
	 * Like
75
	 *
76
	 * @var array
77
	 **/
78
	public $_ion_like = array();
79
80
	/**
81
	 * Limit
82
	 *
83
	 * @var string
84
	 **/
85
	public $_ion_limit = NULL;
86
87
	/**
88
	 * Offset
89
	 *
90
	 * @var string
91
	 **/
92
	public $_ion_offset = NULL;
93
94
	/**
95
	 * Order By
96
	 *
97
	 * @var string
98
	 **/
99
	public $_ion_order_by = NULL;
100
101
	/**
102
	 * Order
103
	 *
104
	 * @var string
105
	 **/
106
	public $_ion_order = NULL;
107
108
	/**
109
	 * Hooks
110
	 *
111
	 * @var object
112
	 **/
113
	protected $_ion_hooks;
114
115
	/**
116
	 * Response
117
	 *
118
	 * @var string
119
	 **/
120
	protected $response = NULL;
121
122
	/**
123
	 * message (uses lang file)
124
	 *
125
	 * @var string
126
	 **/
127
	protected $messages;
128
129
	/**
130
	 * error message (uses lang file)
131
	 *
132
	 * @var string
133
	 **/
134
	protected $errors;
135
136
	/**
137
	 * error start delimiter
138
	 *
139
	 * @var string
140
	 **/
141
	protected $error_start_delimiter;
142
143
	/**
144
	 * error end delimiter
145
	 *
146
	 * @var string
147
	 **/
148
	protected $error_end_delimiter;
149
150
	/**
151
	 * caching of users and their groups
152
	 *
153
	 * @var array
154
	 **/
155
	public $_cache_user_in_group = array();
156
157
	/**
158
	 * caching of groups
159
	 *
160
	 * @var array
161
	 **/
162
	protected $_cache_groups = array();
163
164
	public function __construct()
165
	{
166
		parent::__construct();
167
		$this->load->database();
168
		$this->config->load('ion_auth', TRUE);
169
		$this->load->helper('cookie');
170
		$this->load->helper('date');
171
		$this->lang->load('ion_auth');
172
173
		// initialize db tables data
174
		$this->tables  = $this->config->item('tables', 'ion_auth');
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->config->item('tables', 'ion_auth') of type string or null is incompatible with the declared type array of property $tables.

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...
175
176
		//initialize data
177
		$this->identity_column = $this->config->item('identity', 'ion_auth');
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
178
		$this->store_salt      = $this->config->item('store_salt', 'ion_auth');
0 ignored issues
show
Bug introduced by
The property store_salt does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
179
		$this->salt_length     = $this->config->item('salt_length', 'ion_auth');
0 ignored issues
show
Bug introduced by
The property salt_length does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
180
		$this->join			   = $this->config->item('join', 'ion_auth');
0 ignored issues
show
Bug introduced by
The property join does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
181
182
183
		// initialize hash method options (Bcrypt)
184
		$this->hash_method = $this->config->item('hash_method', 'ion_auth');
0 ignored issues
show
Bug introduced by
The property hash_method does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
185
		$this->default_rounds = $this->config->item('default_rounds', 'ion_auth');
0 ignored issues
show
Bug introduced by
The property default_rounds does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
186
		$this->random_rounds = $this->config->item('random_rounds', 'ion_auth');
0 ignored issues
show
Bug introduced by
The property random_rounds does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
187
		$this->min_rounds = $this->config->item('min_rounds', 'ion_auth');
0 ignored issues
show
Bug introduced by
The property min_rounds does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
188
		$this->max_rounds = $this->config->item('max_rounds', 'ion_auth');
0 ignored issues
show
Bug introduced by
The property max_rounds does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
189
190
191
		// initialize messages and error
192
		$this->messages    = array();
0 ignored issues
show
Documentation Bug introduced by
It seems like array() of type array is incompatible with the declared type string of property $messages.

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...
193
		$this->errors      = array();
0 ignored issues
show
Documentation Bug introduced by
It seems like array() of type array is incompatible with the declared type string of property $errors.

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...
194
		$delimiters_source = $this->config->item('delimiters_source', 'ion_auth');
195
196
		// load the error delimeters either from the config file or use what's been supplied to form validation
197
		if ($delimiters_source === 'form_validation')
198
		{
199
			// load in delimiters from form_validation
200
			// to keep this simple we'll load the value using reflection since these properties are protected
201
			$this->load->library('form_validation');
202
			$form_validation_class = new ReflectionClass("CI_Form_validation");
203
204
			$error_prefix = $form_validation_class->getProperty("_error_prefix");
205
			$error_prefix->setAccessible(TRUE);
206
			$this->error_start_delimiter = $error_prefix->getValue($this->form_validation);
207
			$this->message_start_delimiter = $this->error_start_delimiter;
0 ignored issues
show
Bug introduced by
The property message_start_delimiter does not seem to exist. Did you mean limiter?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
208
209
			$error_suffix = $form_validation_class->getProperty("_error_suffix");
210
			$error_suffix->setAccessible(TRUE);
211
			$this->error_end_delimiter = $error_suffix->getValue($this->form_validation);
212
			$this->message_end_delimiter = $this->error_end_delimiter;
0 ignored issues
show
Bug introduced by
The property message_end_delimiter does not seem to exist. Did you mean limiter?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
213
		}
214
		else
215
		{
216
			// use delimiters from config
217
			$this->message_start_delimiter = $this->config->item('message_start_delimiter', 'ion_auth');
0 ignored issues
show
Bug introduced by
The property message_start_delimiter does not seem to exist. Did you mean limiter?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
218
			$this->message_end_delimiter   = $this->config->item('message_end_delimiter', 'ion_auth');
0 ignored issues
show
Bug introduced by
The property message_end_delimiter does not seem to exist. Did you mean limiter?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
219
			$this->error_start_delimiter   = $this->config->item('error_start_delimiter', 'ion_auth');
220
			$this->error_end_delimiter     = $this->config->item('error_end_delimiter', 'ion_auth');
221
		}
222
223
224
		// initialize our hooks object
225
		$this->_ion_hooks = new stdClass;
226
227
		// load the bcrypt class if needed
228
		if ($this->hash_method == 'bcrypt') {
229
			if ($this->random_rounds)
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->random_rounds of type string|null is loosely compared to true; this is ambiguous if the string can be empty. 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 string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
230
			{
231
				$rand = rand($this->min_rounds,$this->max_rounds);
232
				$params = array('rounds' => $rand);
233
			}
234
			else
235
			{
236
				$params = array('rounds' => $this->default_rounds);
237
			}
238
239
			$params['salt_prefix'] = $this->config->item('salt_prefix', 'ion_auth');
240
			$this->load->library('bcrypt',$params);
241
		}
242
243
		$this->trigger_events('model_constructor');
244
	}
245
246
	/**
247
	 * Misc functions
248
	 *
249
	 * Hash password : Hashes the password to be stored in the database.
250
	 * Hash password db : This function takes a password and validates it
251
	 * against an entry in the users table.
252
	 * Salt : Generates a random salt value.
253
	 *
254
	 * @author Mathew
255
	 */
256
257
	/**
258
	 * Hashes the password to be stored in the database.
259
	 *
260
	 * @return void
261
	 * @author Mathew
262
	 **/
263
	public function hash_password($password, $salt=false, $use_sha1_override=FALSE)
264
	{
265
		if (empty($password))
266
		{
267
			return FALSE;
268
		}
269
270
		// bcrypt
271
		if ($use_sha1_override === FALSE && $this->hash_method == 'bcrypt')
272
		{
273
			return $this->bcrypt->hash($password);
274
		}
275
276
277
		if ($this->store_salt && $salt)
278
		{
279
			return  sha1($password . $salt);
280
		}
281
		else
282
		{
283
			$salt = $this->salt();
284
			return  $salt . substr(sha1($salt . $password), 0, -$this->salt_length);
285
		}
286
	}
287
288
	/**
289
	 * This function takes a password and validates it
290
	 * against an entry in the users table.
291
	 *
292
	 * @return void
293
	 * @author Mathew
294
	 **/
295
	public function hash_password_db($id, $password, $use_sha1_override=FALSE)
296
	{
297
		if (empty($id) || empty($password))
298
		{
299
			return FALSE;
300
		}
301
302
		$this->trigger_events('extra_where');
303
304
		$query = $this->db->select('password, salt')
305
		                  ->where('id', $id)
306
		                  ->limit(1)
307
		                  ->order_by('id', 'desc')
308
		                  ->get($this->tables['users']);
309
310
		$hash_password_db = $query->row();
311
312
		if ($query->num_rows() !== 1)
313
		{
314
			return FALSE;
315
		}
316
317
		// bcrypt
318
		if ($use_sha1_override === FALSE && $this->hash_method == 'bcrypt')
319
		{
320
			if ($this->bcrypt->verify($password,$hash_password_db->password))
321
			{
322
				return TRUE;
323
			}
324
325
			return FALSE;
326
		}
327
328
		// sha1
329
		if ($this->store_salt)
330
		{
331
			$db_password = sha1($password . $hash_password_db->salt);
332
		}
333
		else
334
		{
335
			$salt = substr($hash_password_db->password, 0, $this->salt_length);
336
337
			$db_password =  $salt . substr(sha1($salt . $password), 0, -$this->salt_length);
338
		}
339
340
		if($db_password == $hash_password_db->password)
341
		{
342
			return TRUE;
343
		}
344
		else
345
		{
346
			return FALSE;
347
		}
348
	}
349
350
	/**
351
	 * Generates a random salt value for forgotten passwords or any other keys. Uses SHA1.
352
	 *
353
	 * @return void
354
	 * @author Mathew
355
	 **/
356
	public function hash_code($password)
357
	{
358
		return $this->hash_password($password, FALSE, TRUE);
359
	}
360
361
	/**
362
	 * Generates a random salt value.
363
	 *
364
	 * Salt generation code taken from https://github.com/ircmaxell/password_compat/blob/master/lib/password.php
365
	 *
366
	 * @return void
367
	 * @author Anthony Ferrera
368
	 **/
369
	public function salt()
370
	{
371
372
		$raw_salt_len = 16;
373
374
 		$buffer = '';
375
        $buffer_valid = false;
376
377
        if (function_exists('random_bytes')) {
378
		  $buffer = random_bytes($raw_salt_len);
379
		  if ($buffer) {
380
		    $buffer_valid = true;
381
		  }
382
		}
383
384
		if (!$buffer_valid && function_exists('mcrypt_create_iv') && !defined('PHALANGER')) {
385
		     $buffer = mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM);
386
		    if ($buffer) {
387
		        $buffer_valid = true;
388
		    }
389
		}
390
391
        if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) {
392
            $buffer = openssl_random_pseudo_bytes($raw_salt_len);
393
            if ($buffer) {
394
                $buffer_valid = true;
395
            }
396
        }
397
398
        if (!$buffer_valid && @is_readable('/dev/urandom')) {
399
            $f = fopen('/dev/urandom', 'r');
400
            $read = strlen($buffer);
401
            while ($read < $raw_salt_len) {
402
                $buffer .= fread($f, $raw_salt_len - $read);
403
                $read = strlen($buffer);
404
            }
405
            fclose($f);
406
            if ($read >= $raw_salt_len) {
407
                $buffer_valid = true;
408
            }
409
        }
410
411
        if (!$buffer_valid || strlen($buffer) < $raw_salt_len) {
412
            $bl = strlen($buffer);
413
            for ($i = 0; $i < $raw_salt_len; $i++) {
414
                if ($i < $bl) {
415
                    $buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255));
416
                } else {
417
                    $buffer .= chr(mt_rand(0, 255));
418
                }
419
            }
420
        }
421
422
        $salt = $buffer;
423
424
        // encode string with the Base64 variant used by crypt
425
        $base64_digits   = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
426
        $bcrypt64_digits = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
427
        $base64_string   = base64_encode($salt);
428
        $salt = strtr(rtrim($base64_string, '='), $base64_digits, $bcrypt64_digits);
429
430
	    $salt = substr($salt, 0, $this->salt_length);
431
432
433
		return $salt;
434
435
	}
436
437
	/**
438
	 * Activation functions
439
	 *
440
	 * Activate : Validates and removes activation code.
441
	 * Deactivate : Updates a users row with an activation code.
442
	 *
443
	 * @author Mathew
444
	 */
445
446
	/**
447
	 * activate
448
	 *
449
	 * @return void
450
	 * @author Mathew
451
	 **/
452
	public function activate($id, $code = false)
453
	{
454
		$this->trigger_events('pre_activate');
455
456
		if ($code !== FALSE)
457
		{
458
			$query = $this->db->select($this->identity_column)
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
459
			                  ->where('activation_code', $code)
460
			                  ->where('id', $id)
461
			                  ->limit(1)
462
		    				  ->order_by('id', 'desc')
463
			                  ->get($this->tables['users']);
464
465
			$result = $query->row();
0 ignored issues
show
Unused Code introduced by
$result 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...
466
467
			if ($query->num_rows() !== 1)
468
			{
469
				$this->trigger_events(array('post_activate', 'post_activate_unsuccessful'));
470
				$this->set_error('activate_unsuccessful');
471
				return FALSE;
472
			}
473
474
			$data = array(
475
			    'activation_code' => NULL,
476
			    'active'          => 1
477
			);
478
479
			$this->trigger_events('extra_where');
480
			$this->db->update($this->tables['users'], $data, array('id' => $id));
481
		}
482
		else
483
		{
484
			$data = array(
485
			    'activation_code' => NULL,
486
			    'active'          => 1
487
			);
488
489
490
			$this->trigger_events('extra_where');
491
			$this->db->update($this->tables['users'], $data, array('id' => $id));
492
		}
493
494
495
		$return = $this->db->affected_rows() == 1;
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class CI_DB_query_builder as the method affected_rows() does only exist in the following sub-classes of CI_DB_query_builder: CI_DB_cubrid_driver, CI_DB_ibase_driver, CI_DB_mssql_driver, CI_DB_mysql_driver, CI_DB_mysqli_driver, CI_DB_oci8_driver, CI_DB_pdo_4d_driver, CI_DB_pdo_cubrid_driver, CI_DB_pdo_dblib_driver, CI_DB_pdo_driver, CI_DB_pdo_firebird_driver, CI_DB_pdo_ibm_driver, CI_DB_pdo_informix_driver, CI_DB_pdo_mysql_driver, CI_DB_pdo_oci_driver, CI_DB_pdo_odbc_driver, CI_DB_pdo_pgsql_driver, CI_DB_pdo_sqlite_driver, CI_DB_pdo_sqlsrv_driver, CI_DB_postgre_driver, CI_DB_sqlite3_driver, CI_DB_sqlite_driver, CI_DB_sqlsrv_driver. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
496
		if ($return)
497
		{
498
			$this->trigger_events(array('post_activate', 'post_activate_successful'));
499
			$this->set_message('activate_successful');
500
		}
501
		else
502
		{
503
			$this->trigger_events(array('post_activate', 'post_activate_unsuccessful'));
504
			$this->set_error('activate_unsuccessful');
505
		}
506
507
508
		return $return;
509
	}
510
511
512
	/**
513
	 * Deactivate
514
	 *
515
	 * @return void
516
	 * @author Mathew
517
	 **/
518
	public function deactivate($id = NULL)
519
	{
520
		$this->trigger_events('deactivate');
521
522
		if (!isset($id))
523
		{
524
			$this->set_error('deactivate_unsuccessful');
525
			return FALSE;
526
		}
527
                elseif($this->ion_auth->logged_in() && $this->user()->row()->id == $id)
0 ignored issues
show
Bug introduced by
The method logged_in() does not seem to exist on object<Ion_auth_model>.

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...
528
                {
529
                        $this->set_error('deactivate_current_user_unsuccessful');
530
                        return FALSE;
531
                }
532
533
		$activation_code       = sha1(md5(microtime()));
534
		$this->activation_code = $activation_code;
535
536
		$data = array(
537
		    'activation_code' => $activation_code,
538
		    'active'          => 0
539
		);
540
541
		$this->trigger_events('extra_where');
542
		$this->db->update($this->tables['users'], $data, array('id' => $id));
543
544
		$return = $this->db->affected_rows() == 1;
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class CI_DB_query_builder as the method affected_rows() does only exist in the following sub-classes of CI_DB_query_builder: CI_DB_cubrid_driver, CI_DB_ibase_driver, CI_DB_mssql_driver, CI_DB_mysql_driver, CI_DB_mysqli_driver, CI_DB_oci8_driver, CI_DB_pdo_4d_driver, CI_DB_pdo_cubrid_driver, CI_DB_pdo_dblib_driver, CI_DB_pdo_driver, CI_DB_pdo_firebird_driver, CI_DB_pdo_ibm_driver, CI_DB_pdo_informix_driver, CI_DB_pdo_mysql_driver, CI_DB_pdo_oci_driver, CI_DB_pdo_odbc_driver, CI_DB_pdo_pgsql_driver, CI_DB_pdo_sqlite_driver, CI_DB_pdo_sqlsrv_driver, CI_DB_postgre_driver, CI_DB_sqlite3_driver, CI_DB_sqlite_driver, CI_DB_sqlsrv_driver. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
545
		if ($return)
546
			$this->set_message('deactivate_successful');
547
		else
548
			$this->set_error('deactivate_unsuccessful');
549
550
		return $return;
551
	}
552
553
	public function clear_forgotten_password_code($code) {
554
555
		if (empty($code))
556
		{
557
			return FALSE;
558
		}
559
560
		$this->db->where('forgotten_password_code', $code);
561
562
		if ($this->db->count_all_results($this->tables['users']) > 0)
563
		{
564
			$data = array(
565
			    'forgotten_password_code' => NULL,
566
			    'forgotten_password_time' => NULL
567
			);
568
569
			$this->db->update($this->tables['users'], $data, array('forgotten_password_code' => $code));
570
571
			return TRUE;
572
		}
573
574
		return FALSE;
575
	}
576
577
	/**
578
	 * reset password
579
	 *
580
	 * @return bool
581
	 * @author Mathew
582
	 **/
583
	public function reset_password($identity, $new) {
584
		$this->trigger_events('pre_change_password');
585
586
		if (!$this->identity_check($identity)) {
587
			$this->trigger_events(array('post_change_password', 'post_change_password_unsuccessful'));
588
			return FALSE;
589
		}
590
591
		$this->trigger_events('extra_where');
592
593
		$query = $this->db->select('id, password, salt')
594
		                  ->where($this->identity_column, $identity)
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
595
		                  ->limit(1)
596
		    			  ->order_by('id', 'desc')
597
		                  ->get($this->tables['users']);
598
599 View Code Duplication
		if ($query->num_rows() !== 1)
600
		{
601
			$this->trigger_events(array('post_change_password', 'post_change_password_unsuccessful'));
602
			$this->set_error('password_change_unsuccessful');
603
			return FALSE;
604
		}
605
606
		$result = $query->row();
607
608
		$new = $this->hash_password($new, $result->salt);
609
610
		// store the new password and reset the remember code so all remembered instances have to re-login
611
		// also clear the forgotten password code
612
		$data = array(
613
		    'password' => $new,
614
		    'remember_code' => NULL,
615
		    'forgotten_password_code' => NULL,
616
		    'forgotten_password_time' => NULL,
617
		);
618
619
		$this->trigger_events('extra_where');
620
		$this->db->update($this->tables['users'], $data, array($this->identity_column => $identity));
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
621
622
		$return = $this->db->affected_rows() == 1;
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class CI_DB_query_builder as the method affected_rows() does only exist in the following sub-classes of CI_DB_query_builder: CI_DB_cubrid_driver, CI_DB_ibase_driver, CI_DB_mssql_driver, CI_DB_mysql_driver, CI_DB_mysqli_driver, CI_DB_oci8_driver, CI_DB_pdo_4d_driver, CI_DB_pdo_cubrid_driver, CI_DB_pdo_dblib_driver, CI_DB_pdo_driver, CI_DB_pdo_firebird_driver, CI_DB_pdo_ibm_driver, CI_DB_pdo_informix_driver, CI_DB_pdo_mysql_driver, CI_DB_pdo_oci_driver, CI_DB_pdo_odbc_driver, CI_DB_pdo_pgsql_driver, CI_DB_pdo_sqlite_driver, CI_DB_pdo_sqlsrv_driver, CI_DB_postgre_driver, CI_DB_sqlite3_driver, CI_DB_sqlite_driver, CI_DB_sqlsrv_driver. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
623 View Code Duplication
		if ($return)
624
		{
625
			$this->trigger_events(array('post_change_password', 'post_change_password_successful'));
626
			$this->set_message('password_change_successful');
627
		}
628
		else
629
		{
630
			$this->trigger_events(array('post_change_password', 'post_change_password_unsuccessful'));
631
			$this->set_error('password_change_unsuccessful');
632
		}
633
634
		return $return;
635
	}
636
637
	/**
638
	 * change password
639
	 *
640
	 * @return bool
641
	 * @author Mathew
642
	 **/
643
	public function change_password($identity, $old, $new)
644
	{
645
		$this->trigger_events('pre_change_password');
646
647
		$this->trigger_events('extra_where');
648
649
		$query = $this->db->select('id, password, salt')
650
		                  ->where($this->identity_column, $identity)
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
651
		                  ->limit(1)
652
		    			  ->order_by('id', 'desc')
653
		                  ->get($this->tables['users']);
654
655 View Code Duplication
		if ($query->num_rows() !== 1)
656
		{
657
			$this->trigger_events(array('post_change_password', 'post_change_password_unsuccessful'));
658
			$this->set_error('password_change_unsuccessful');
659
			return FALSE;
660
		}
661
662
		$user = $query->row();
663
664
		$old_password_matches = $this->hash_password_db($user->id, $old);
665
666
		if ($old_password_matches === TRUE)
667
		{
668
			// store the new password and reset the remember code so all remembered instances have to re-login
669
			$hashed_new_password  = $this->hash_password($new, $user->salt);
670
			$data = array(
671
			    'password' => $hashed_new_password,
672
			    'remember_code' => NULL,
673
			);
674
675
			$this->trigger_events('extra_where');
676
677
			$successfully_changed_password_in_db = $this->db->update($this->tables['users'], $data, array($this->identity_column => $identity));
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
678 View Code Duplication
			if ($successfully_changed_password_in_db)
679
			{
680
				$this->trigger_events(array('post_change_password', 'post_change_password_successful'));
681
				$this->set_message('password_change_successful');
682
			}
683
			else
684
			{
685
				$this->trigger_events(array('post_change_password', 'post_change_password_unsuccessful'));
686
				$this->set_error('password_change_unsuccessful');
687
			}
688
689
			return $successfully_changed_password_in_db;
690
		}
691
692
		$this->set_error('password_change_unsuccessful');
693
		return FALSE;
694
	}
695
696
	/**
697
	 * Checks username
698
	 *
699
	 * @return bool
700
	 * @author Mathew
701
	 **/
702 View Code Duplication
	public function username_check($username = '')
703
	{
704
		$this->trigger_events('username_check');
705
706
		if (empty($username))
707
		{
708
			return FALSE;
709
		}
710
711
		$this->trigger_events('extra_where');
712
713
		return $this->db->where('username', $username)
714
										->group_by("id")
715
										->order_by("id", "ASC")
716
										->limit(1)
717
		                ->count_all_results($this->tables['users']) > 0;
718
	}
719
720
	/**
721
	 * Checks email
722
	 *
723
	 * @return bool
724
	 * @author Mathew
725
	 **/
726 View Code Duplication
	public function email_check($email = '')
727
	{
728
		$this->trigger_events('email_check');
729
730
		if (empty($email))
731
		{
732
			return FALSE;
733
		}
734
735
		$this->trigger_events('extra_where');
736
737
		return $this->db->where('email', $email)
738
										->group_by("id")
739
										->order_by("id", "ASC")
740
										->limit(1)
741
		                ->count_all_results($this->tables['users']) > 0;
742
	}
743
744
	/**
745
	 * Identity check
746
	 *
747
	 * @return bool
748
	 * @author Mathew
749
	 **/
750
	public function identity_check($identity = '')
751
	{
752
		$this->trigger_events('identity_check');
753
754
		if (empty($identity))
755
		{
756
			return FALSE;
757
		}
758
759
		return $this->db->where($this->identity_column, $identity)
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
760
		                ->count_all_results($this->tables['users']) > 0;
761
	}
762
763
	/**
764
	 * Insert a forgotten password key.
765
	 *
766
	 * @return bool
767
	 * @author Mathew
768
	 * @updated Ryan
769
	 * @updated 52aa456eef8b60ad6754b31fbdcc77bb
770
	 **/
771
	public function forgotten_password($identity)
772
	{
773
		if (empty($identity))
774
		{
775
			$this->trigger_events(array('post_forgotten_password', 'post_forgotten_password_unsuccessful'));
776
			return FALSE;
777
		}
778
779
		// All some more randomness
780
		$activation_code_part = "";
781
		if(function_exists("openssl_random_pseudo_bytes")) {
782
			$activation_code_part = openssl_random_pseudo_bytes(128);
783
		}
784
785
		for($i=0;$i<1024;$i++) {
786
			$activation_code_part = sha1($activation_code_part . mt_rand() . microtime());
787
		}
788
789
		$key = $this->hash_code($activation_code_part.$identity);
790
791
		// If enable query strings is set, then we need to replace any unsafe characters so that the code can still work
792
		if ($key != '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') == FALSE)
793
		{
794
			// preg_quote() in PHP 5.3 escapes -, so the str_replace() and addition of - to preg_quote() is to maintain backwards
795
			// compatibility as many are unaware of how characters in the permitted_uri_chars will be parsed as a regex pattern
796
			if ( ! preg_match("|^[".str_replace(array('\\-', '\-'), '-', preg_quote($this->config->item('permitted_uri_chars'), '-'))."]+$|i", $key))
797
			{
798
				$key = preg_replace("/[^".$this->config->item('permitted_uri_chars')."]+/i", "-", $key);
799
			}
800
		}
801
802
		// Limit to 40 characters since that's how our DB field is setup
803
		$this->forgotten_password_code = substr($key, 0, 40);
804
805
		$this->trigger_events('extra_where');
806
807
		$update = array(
808
		    'forgotten_password_code' => $key,
809
		    'forgotten_password_time' => time()
810
		);
811
812
		$this->db->update($this->tables['users'], $update, array($this->identity_column => $identity));
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
813
814
		$return = $this->db->affected_rows() == 1;
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class CI_DB_query_builder as the method affected_rows() does only exist in the following sub-classes of CI_DB_query_builder: CI_DB_cubrid_driver, CI_DB_ibase_driver, CI_DB_mssql_driver, CI_DB_mysql_driver, CI_DB_mysqli_driver, CI_DB_oci8_driver, CI_DB_pdo_4d_driver, CI_DB_pdo_cubrid_driver, CI_DB_pdo_dblib_driver, CI_DB_pdo_driver, CI_DB_pdo_firebird_driver, CI_DB_pdo_ibm_driver, CI_DB_pdo_informix_driver, CI_DB_pdo_mysql_driver, CI_DB_pdo_oci_driver, CI_DB_pdo_odbc_driver, CI_DB_pdo_pgsql_driver, CI_DB_pdo_sqlite_driver, CI_DB_pdo_sqlsrv_driver, CI_DB_postgre_driver, CI_DB_sqlite3_driver, CI_DB_sqlite_driver, CI_DB_sqlsrv_driver. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
815
816
		if ($return)
817
			$this->trigger_events(array('post_forgotten_password', 'post_forgotten_password_successful'));
818
		else
819
			$this->trigger_events(array('post_forgotten_password', 'post_forgotten_password_unsuccessful'));
820
821
		return $return;
822
	}
823
824
	/**
825
	 * Forgotten Password Complete
826
	 *
827
	 * @return string
828
	 * @author Mathew
829
	 **/
830
	public function forgotten_password_complete($code, $salt=FALSE)
831
	{
832
		$this->trigger_events('pre_forgotten_password_complete');
833
834
		if (empty($code))
835
		{
836
			$this->trigger_events(array('post_forgotten_password_complete', 'post_forgotten_password_complete_unsuccessful'));
837
			return FALSE;
838
		}
839
840
		$profile = $this->where('forgotten_password_code', $code)->users()->row(); //pass the code to profile
841
842
		if ($profile) {
843
844
			if ($this->config->item('forgot_password_expiration', 'ion_auth') > 0) {
845
				//Make sure it isn't expired
846
				$expiration = $this->config->item('forgot_password_expiration', 'ion_auth');
847
				if (time() - $profile->forgotten_password_time > $expiration) {
848
					//it has expired
849
					$this->set_error('forgot_password_expired');
850
					$this->trigger_events(array('post_forgotten_password_complete', 'post_forgotten_password_complete_unsuccessful'));
851
					return FALSE;
852
				}
853
			}
854
855
			$password = $this->salt();
856
857
			$data = array(
858
			    'password'                => $this->hash_password($password, $salt),
859
			    'forgotten_password_code' => NULL,
860
			    'active'                  => 1,
861
			 );
862
863
			$this->db->update($this->tables['users'], $data, array('forgotten_password_code' => $code));
864
865
			$this->trigger_events(array('post_forgotten_password_complete', 'post_forgotten_password_complete_successful'));
866
			return $password;
867
		}
868
869
		$this->trigger_events(array('post_forgotten_password_complete', 'post_forgotten_password_complete_unsuccessful'));
870
		return FALSE;
871
	}
872
873
	/**
874
	 * register
875
	 *
876
	 * @return bool
877
	 * @author Mathew
878
	 **/
879
	public function register($identity, $password, $email, $additional_data = array(), $groups = array())
880
	{
881
		$this->trigger_events('pre_register');
882
883
		$manual_activation = $this->config->item('manual_activation', 'ion_auth');
884
885
		if ($this->identity_check($identity))
886
		{
887
			$this->set_error('account_creation_duplicate_identity');
888
			return FALSE;
889
		}
890
		elseif ( !$this->config->item('default_group', 'ion_auth') && empty($groups) )
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->config->item('default_group', 'ion_auth') of type string|null is loosely compared to false; this is ambiguous if the string can be empty. 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 string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
891
		{
892
			$this->set_error('account_creation_missing_default_group');
893
			return FALSE;
894
		}
895
896
		// check if the default set in config exists in database
897
		$query = $this->db->get_where($this->tables['groups'],array('name' => $this->config->item('default_group', 'ion_auth')),1)->row();
0 ignored issues
show
Documentation introduced by
array('name' => $this->c...lt_group', 'ion_auth')) is of type array<string,string|null,{"name":"string|null"}>, 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...
898
		if( !isset($query->id) && empty($groups) )
899
		{
900
			$this->set_error('account_creation_invalid_default_group');
901
			return FALSE;
902
		}
903
904
		// capture default group details
905
		$default_group = $query;
906
907
		// IP Address
908
		$ip_address = $this->_prepare_ip($this->input->ip_address());
909
		$salt       = $this->store_salt ? $this->salt() : FALSE;
910
		$password   = $this->hash_password($password, $salt);
0 ignored issues
show
Bug introduced by
It seems like $salt defined by $this->store_salt ? $this->salt() : FALSE on line 909 can also be of type string; however, Ion_auth_model::hash_password() does only seem to accept boolean, 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...
911
912
		// Users table.
913
		$data = array(
914
		    $this->identity_column   => $identity,
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
915
		    'username'   => $identity,
916
		    'password'   => $password,
917
		    'email'      => $email,
918
		    'ip_address' => $ip_address,
919
		    'created_on' => time(),
920
		    'active'     => ($manual_activation === false ? 1 : 0)
921
		);
922
923
		if ($this->store_salt)
924
		{
925
			$data['salt'] = $salt;
926
		}
927
928
		// filter out any data passed that doesnt have a matching column in the users table
929
		// and merge the set user data and the additional data
930
		$user_data = array_merge($this->_filter_data($this->tables['users'], $additional_data), $data);
931
932
		$this->trigger_events('extra_set');
933
934
		$this->db->insert($this->tables['users'], $user_data);
935
936
		$id = $this->db->insert_id($this->tables['users'] . '_id_seq');
0 ignored issues
show
Bug introduced by
The method insert_id() does not exist on CI_DB_query_builder. Did you maybe mean insert()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
937
938
		// add in groups array if it doesn't exists and stop adding into default group if default group ids are set
939
		if( isset($default_group->id) && empty($groups) )
940
		{
941
			$groups[] = $default_group->id;
942
		}
943
944
		if (!empty($groups))
945
		{
946
			// add to groups
947
			foreach ($groups as $group)
948
			{
949
				$this->add_to_group($group, $id);
950
			}
951
		}
952
953
		$this->trigger_events('post_register');
954
955
		return (isset($id)) ? $id : FALSE;
956
	}
957
958
	/**
959
	 * login
960
	 *
961
	 * @return bool
962
	 * @author Mathew
963
	 **/
964
	public function login($identity, $password, $remember=FALSE)
965
	{
966
		$this->trigger_events('pre_login');
967
968
		if (empty($identity) || empty($password))
969
		{
970
			$this->set_error('login_unsuccessful');
971
			return FALSE;
972
		}
973
974
		$this->trigger_events('extra_where');
975
976
		$query = $this->db->select($this->identity_column . ', email, id, password, active, last_login')
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
977
		                  ->where($this->identity_column, $identity)
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
978
		                  ->limit(1)
979
		    			  ->order_by('id', 'desc')
980
		                  ->get($this->tables['users']);
981
982
		if($this->is_max_login_attempts_exceeded($identity))
983
		{
984
			// Hash something anyway, just to take up time
985
			$this->hash_password($password);
986
987
			$this->trigger_events('post_login_unsuccessful');
988
			$this->set_error('login_timeout');
989
990
			return FALSE;
991
		}
992
993
		if ($query->num_rows() === 1)
994
		{
995
			$user = $query->row();
996
997
			$password = $this->hash_password_db($user->id, $password);
998
999
			if ($password === TRUE)
1000
			{
1001
				if ($user->active == 0)
1002
				{
1003
					$this->trigger_events('post_login_unsuccessful');
1004
					$this->set_error('login_unsuccessful_not_active');
1005
1006
					return FALSE;
1007
				}
1008
1009
				$this->set_session($user);
1010
1011
				$this->update_last_login($user->id);
1012
1013
				$this->clear_login_attempts($identity);
1014
1015
				if ($remember && $this->config->item('remember_users', 'ion_auth'))
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->config->item('remember_users', 'ion_auth') of type string|null is loosely compared to true; this is ambiguous if the string can be empty. 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 string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1016
				{
1017
					$this->remember_user($user->id);
1018
				}
1019
1020
				$this->trigger_events(array('post_login', 'post_login_successful'));
1021
				$this->set_message('login_successful');
1022
1023
				return TRUE;
1024
			}
1025
		}
1026
1027
		// Hash something anyway, just to take up time
1028
		$this->hash_password($password);
1029
1030
		$this->increase_login_attempts($identity);
1031
1032
		$this->trigger_events('post_login_unsuccessful');
1033
		$this->set_error('login_unsuccessful');
1034
1035
		return FALSE;
1036
	}
1037
1038
    /**
1039
     * recheck_session verifies if the session should be rechecked according to
1040
     * the configuration item recheck_timer. If it does, then it will check if the user is still active
1041
     * @return bool
1042
     */
1043
	public function recheck_session()
1044
    {
1045
        $recheck = (null !== $this->config->item('recheck_timer', 'ion_auth')) ? $this->config->item('recheck_timer', 'ion_auth') : 0;
1046
1047
        if($recheck!==0)
1048
        {
1049
            $last_login = $this->session->userdata('last_check');
1050
            if($last_login+$recheck < time())
1051
            {
1052
                $query = $this->db->select('id')
1053
                    ->where(array($this->identity_column=>$this->session->userdata('identity'),'active'=>'1'))
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1054
                    ->limit(1)
1055
                    ->order_by('id', 'desc')
1056
                    ->get($this->tables['users']);
1057
                if ($query->num_rows() === 1)
1058
                {
1059
                    $this->session->set_userdata('last_check',time());
1060
                }
1061
                else
1062
                {
1063
                    $this->trigger_events('logout');
1064
1065
                    $identity = $this->config->item('identity', 'ion_auth');
1066
1067 View Code Duplication
                    if (substr(CI_VERSION, 0, 1) == '2')
1068
                    {
1069
                        $this->session->unset_userdata( array($identity => '', 'id' => '', 'user_id' => '') );
1070
                    }
1071
                    else
1072
                    {
1073
                        $this->session->unset_userdata( array($identity, 'id', 'user_id') );
1074
                    }
1075
                    return false;
1076
                }
1077
            }
1078
        }
1079
1080
        return (bool) $this->session->userdata('identity');
1081
    }
1082
1083
	/**
1084
	 * is_max_login_attempts_exceeded
1085
	 * Based on code from Tank Auth, by Ilya Konyukhov (https://github.com/ilkon/Tank-Auth)
1086
	 *
1087
	 * @param string $identity: user's identity
0 ignored issues
show
Documentation introduced by
There is no parameter named $identity:. Did you maybe mean $identity?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
1088
	 * @param string $ip_address: IP address
0 ignored issues
show
Documentation introduced by
There is no parameter named $ip_address:. Did you maybe mean $ip_address?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
1089
	 *                            Only used if track_login_ip_address set to TRUE.
1090
	 *                            If NULL (default value), current IP address is used.
1091
	 *                            Use get_last_attempt_ip($identity) to retrieve user's last IP
1092
	 * @return boolean
1093
	 **/
1094
	public function is_max_login_attempts_exceeded($identity, $ip_address = NULL) {
1095
		if ($this->config->item('track_login_attempts', 'ion_auth')) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->config->item('tra..._attempts', 'ion_auth') of type string|null is loosely compared to true; this is ambiguous if the string can be empty. 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 string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1096
			$max_attempts = $this->config->item('maximum_login_attempts', 'ion_auth');
1097
			if ($max_attempts > 0) {
1098
				$attempts = $this->get_attempts_num($identity, $ip_address);
1099
				return $attempts >= $max_attempts;
1100
			}
1101
		}
1102
		return FALSE;
1103
	}
1104
1105
	/**
1106
	 * Get number of attempts to login occured from given IP-address or identity
1107
	 * Based on code from Tank Auth, by Ilya Konyukhov (https://github.com/ilkon/Tank-Auth)
1108
	 *
1109
	 * @param string $identity: user's identity
0 ignored issues
show
Documentation introduced by
There is no parameter named $identity:. Did you maybe mean $identity?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
1110
	 * @param string $ip_address: IP address
0 ignored issues
show
Documentation introduced by
There is no parameter named $ip_address:. Did you maybe mean $ip_address?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
1111
	 *                            Only used if track_login_ip_address set to TRUE.
1112
	 *                            If NULL (default value), current IP address is used.
1113
	 *                            Use get_last_attempt_ip($identity) to retrieve user's last IP
1114
	 * @return int
1115
	 */
1116
	public function get_attempts_num($identity, $ip_address = NULL)
1117
	{
1118
        if ($this->config->item('track_login_attempts', 'ion_auth')) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->config->item('tra..._attempts', 'ion_auth') of type string|null is loosely compared to true; this is ambiguous if the string can be empty. 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 string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1119
            $this->db->select('1', FALSE);
1120
            $this->db->where('login', $identity);
1121 View Code Duplication
            if ($this->config->item('track_login_ip_address', 'ion_auth')) {
1122
	        if (!isset($ip_address)) {
1123
	            $ip_address = $this->_prepare_ip($this->input->ip_address());
1124
	        }
1125
            	$this->db->where('ip_address', $ip_address);
1126
            }
1127
            $this->db->where('time >', time() - $this->config->item('lockout_time', 'ion_auth'), FALSE);
1128
            $qres = $this->db->get($this->tables['login_attempts']);
1129
            return $qres->num_rows();
1130
        }
1131
        return 0;
1132
	}
1133
1134
	/**
1135
	 * Get a boolean to determine if an account should be locked out due to
1136
	 * exceeded login attempts within a given period
1137
	 *
1138
	 * This function is only a wrapper for is_max_login_attempts_exceeded() since it
1139
	 * only retrieve attempts within the given period.
1140
	 * It is kept for retrocompatibility purpose.
1141
	 *
1142
	 * @param string $identity: user's identity
0 ignored issues
show
Documentation introduced by
There is no parameter named $identity:. Did you maybe mean $identity?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
1143
	 * @param string $ip_address: IP address
0 ignored issues
show
Documentation introduced by
There is no parameter named $ip_address:. Did you maybe mean $ip_address?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
1144
	 *                            Only used if track_login_ip_address set to TRUE.
1145
	 *                            If NULL (default value), current IP address is used.
1146
	 *                            Use get_last_attempt_ip($identity) to retrieve user's last IP
1147
	 * @return boolean
1148
	 */
1149
	public function is_time_locked_out($identity, $ip_address = NULL) {
1150
		return $this->is_max_login_attempts_exceeded($identity, $ip_address);
1151
	}
1152
1153
	/**
1154
	 * Get the time of the last time a login attempt occured from given IP-address or identity
1155
	 *
1156
	 * This function is no longer used.
1157
	 * It is kept for retrocompatibility purpose.
1158
	 *
1159
	 * @param string $identity: user's identity
0 ignored issues
show
Documentation introduced by
There is no parameter named $identity:. Did you maybe mean $identity?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
1160
	 * @param string $ip_address: IP address
0 ignored issues
show
Documentation introduced by
There is no parameter named $ip_address:. Did you maybe mean $ip_address?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
1161
	 *                            Only used if track_login_ip_address set to TRUE.
1162
	 *                            If NULL (default value), current IP address is used.
1163
	 *                            Use get_last_attempt_ip($identity) to retrieve user's last IP
1164
	 * @return int
1165
	 */
1166
	public function get_last_attempt_time($identity, $ip_address = NULL) {
1167
		if ($this->config->item('track_login_attempts', 'ion_auth')) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->config->item('tra..._attempts', 'ion_auth') of type string|null is loosely compared to true; this is ambiguous if the string can be empty. 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 string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1168
			$this->db->select('time');
1169
			$this->db->where('login', $identity);
1170 View Code Duplication
			if ($this->config->item('track_login_ip_address', 'ion_auth')) {
1171
				if (!isset($ip_address)) {
1172
					$ip_address = $this->_prepare_ip($this->input->ip_address());
1173
				}
1174
				$this->db->where('ip_address', $ip_address);
1175
			}
1176
			$this->db->order_by('id', 'desc');
1177
			$qres = $this->db->get($this->tables['login_attempts'], 1);
1178
1179
			if($qres->num_rows() > 0) {
1180
				return $qres->row()->time;
1181
			}
1182
		}
1183
1184
		return 0;
1185
	}
1186
1187
	/**
1188
	* Get the IP address of the last time a login attempt occured from given identity
1189
	*
1190
	 * @param string $identity: user's identity
0 ignored issues
show
Documentation introduced by
There is no parameter named $identity:. Did you maybe mean $identity?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
1191
	* @return string
1192
	*/
1193
	public function get_last_attempt_ip($identity) {
1194
		if ($this->config->item('track_login_attempts', 'ion_auth') && $this->config->item('track_login_ip_address', 'ion_auth')) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->config->item('tra..._attempts', 'ion_auth') of type string|null is loosely compared to true; this is ambiguous if the string can be empty. 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 string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1195
			$this->db->select('ip_address');
1196
			$this->db->where('login', $identity);
1197
			$this->db->order_by('id', 'desc');
1198
			$qres = $this->db->get($this->tables['login_attempts'], 1);
1199
1200
			if($qres->num_rows() > 0) {
1201
				return $qres->row()->ip_address;
1202
			}
1203
		}
1204
1205
		return '';
1206
	}
1207
1208
	/**
1209
	 * increase_login_attempts
1210
	 * Based on code from Tank Auth, by Ilya Konyukhov (https://github.com/ilkon/Tank-Auth)
1211
	 *
1212
	 * Note: the current IP address will be used if track_login_ip_address config value is TRUE
1213
	 *
1214
	 * @param string $identity: user's identity
0 ignored issues
show
Documentation introduced by
There is no parameter named $identity:. Did you maybe mean $identity?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
1215
	 **/
1216
	public function increase_login_attempts($identity) {
1217
		if ($this->config->item('track_login_attempts', 'ion_auth')) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->config->item('tra..._attempts', 'ion_auth') of type string|null is loosely compared to true; this is ambiguous if the string can be empty. 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 string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1218
			$data = array('ip_address' => '', 'login' => $identity, 'time' => time());
1219
			if ($this->config->item('track_login_ip_address', 'ion_auth')) {
1220
				$data['ip_address'] = $this->_prepare_ip($this->input->ip_address());
1221
			}
1222
			return $this->db->insert($this->tables['login_attempts'], $data);
1223
		}
1224
		return FALSE;
1225
	}
1226
1227
	/**
1228
	 * clear_login_attempts
1229
	 * Based on code from Tank Auth, by Ilya Konyukhov (https://github.com/ilkon/Tank-Auth)
1230
	 *
1231
	 * @param string $identity: user's identity
0 ignored issues
show
Documentation introduced by
There is no parameter named $identity:. Did you maybe mean $identity?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
1232
	 * @param int $old_attempts_expire_period: in seconds, any attempts older than this value will be removed.
0 ignored issues
show
Documentation introduced by
There is no parameter named $old_attempts_expire_period:. Did you maybe mean $old_attempts_expire_period?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
1233
	 *                                         It is used for regularly purging the attempts table.
1234
	 *                                         (for security reason, minimum value is lockout_time config value)
1235
	 * @param string $ip_address: IP address
0 ignored issues
show
Documentation introduced by
There is no parameter named $ip_address:. Did you maybe mean $ip_address?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
1236
	 *                            Only used if track_login_ip_address set to TRUE.
1237
	 *                            If NULL (default value), current IP address is used.
1238
	 *                            Use get_last_attempt_ip($identity) to retrieve user's last IP
1239
	 **/
1240
	public function clear_login_attempts($identity, $old_attempts_expire_period = 86400, $ip_address = NULL) {
1241
		if ($this->config->item('track_login_attempts', 'ion_auth')) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->config->item('tra..._attempts', 'ion_auth') of type string|null is loosely compared to true; this is ambiguous if the string can be empty. 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 string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1242
			// Make sure $old_attempts_expire_period is at least equals to lockout_time
1243
			$old_attempts_expire_period = max($old_attempts_expire_period, $this->config->item('lockout_time', 'ion_auth'));
1244
1245
			$this->db->where('login', $identity);
1246 View Code Duplication
			if ($this->config->item('track_login_ip_address', 'ion_auth')) {
1247
				if (!isset($ip_address)) {
1248
					$ip_address = $this->_prepare_ip($this->input->ip_address());
1249
				}
1250
				$this->db->where('ip_address', $ip_address);
1251
			}
1252
			// Purge obsolete login attempts
1253
			$this->db->or_where('time <', time() - $old_attempts_expire_period, FALSE);
1254
1255
			return $this->db->delete($this->tables['login_attempts']);
1256
		}
1257
		return FALSE;
1258
	}
1259
1260
	public function limit($limit)
1261
	{
1262
		$this->trigger_events('limit');
1263
		$this->_ion_limit = $limit;
1264
1265
		return $this;
1266
	}
1267
1268
	public function offset($offset)
1269
	{
1270
		$this->trigger_events('offset');
1271
		$this->_ion_offset = $offset;
1272
1273
		return $this;
1274
	}
1275
1276
	public function where($where, $value = NULL)
1277
	{
1278
		$this->trigger_events('where');
1279
1280
		if (!is_array($where))
1281
		{
1282
			$where = array($where => $value);
1283
		}
1284
1285
		array_push($this->_ion_where, $where);
1286
1287
		return $this;
1288
	}
1289
1290
	public function like($like, $value = NULL, $position = 'both')
1291
	{
1292
		$this->trigger_events('like');
1293
1294
		array_push($this->_ion_like, array(
1295
			'like'     => $like,
1296
			'value'    => $value,
1297
			'position' => $position
1298
		));
1299
1300
		return $this;
1301
	}
1302
1303
	public function select($select)
1304
	{
1305
		$this->trigger_events('select');
1306
1307
		$this->_ion_select[] = $select;
1308
1309
		return $this;
1310
	}
1311
1312
	public function order_by($by, $order='desc')
1313
	{
1314
		$this->trigger_events('order_by');
1315
1316
		$this->_ion_order_by = $by;
1317
		$this->_ion_order    = $order;
1318
1319
		return $this;
1320
	}
1321
1322
	public function row()
1323
	{
1324
		$this->trigger_events('row');
1325
1326
		$row = $this->response->row();
0 ignored issues
show
Bug introduced by
The method row cannot be called on $this->response (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
1327
1328
		return $row;
1329
	}
1330
1331
	public function row_array()
1332
	{
1333
		$this->trigger_events(array('row', 'row_array'));
1334
1335
		$row = $this->response->row_array();
0 ignored issues
show
Bug introduced by
The method row_array cannot be called on $this->response (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
1336
1337
		return $row;
1338
	}
1339
1340
	public function result()
1341
	{
1342
		$this->trigger_events('result');
1343
1344
		$result = $this->response->result();
0 ignored issues
show
Bug introduced by
The method result cannot be called on $this->response (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
1345
1346
		return $result;
1347
	}
1348
1349
	public function result_array()
1350
	{
1351
		$this->trigger_events(array('result', 'result_array'));
1352
1353
		$result = $this->response->result_array();
0 ignored issues
show
Bug introduced by
The method result_array cannot be called on $this->response (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
1354
1355
		return $result;
1356
	}
1357
1358
	public function num_rows()
1359
	{
1360
		$this->trigger_events(array('num_rows'));
1361
1362
		$result = $this->response->num_rows();
0 ignored issues
show
Bug introduced by
The method num_rows cannot be called on $this->response (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
1363
1364
		return $result;
1365
	}
1366
1367
	/**
1368
	 * users
1369
	 *
1370
	 * @return object Users
1371
	 * @author Ben Edmunds
1372
	 **/
1373
	public function users($groups = NULL)
1374
	{
1375
		$this->trigger_events('users');
1376
1377
		if (isset($this->_ion_select) && !empty($this->_ion_select))
1378
		{
1379
			foreach ($this->_ion_select as $select)
1380
			{
1381
				$this->db->select($select);
1382
			}
1383
1384
			$this->_ion_select = array();
1385
		}
1386
		else
1387
		{
1388
			//default selects
1389
			$this->db->select(array(
0 ignored issues
show
Documentation introduced by
array($this->tables['use...s'] . '.id as user_id') is of type array<integer,string,{"0..."string","2":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1390
			    $this->tables['users'].'.*',
1391
			    $this->tables['users'].'.id as id',
1392
			    $this->tables['users'].'.id as user_id'
1393
			));
1394
		}
1395
1396
		// filter by group id(s) if passed
1397
		if (isset($groups))
1398
		{
1399
			// build an array if only one group was passed
1400
			if (!is_array($groups))
1401
			{
1402
				$groups = Array($groups);
1403
			}
1404
1405
			// join and then run a where_in against the group ids
1406
			if (isset($groups) && !empty($groups))
1407
			{
1408
				$this->db->distinct();
1409
				$this->db->join(
1410
				    $this->tables['users_groups'],
1411
				    $this->tables['users_groups'].'.'.$this->join['users'].'='.$this->tables['users'].'.id',
1412
				    'inner'
1413
				);
1414
			}
1415
1416
			// verify if group name or group id was used and create and put elements in different arrays
1417
			$group_ids = array();
1418
			$group_names = array();
1419
			foreach($groups as $group)
0 ignored issues
show
Bug introduced by
The expression $groups of type null|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1420
			{
1421
				if(is_numeric($group)) $group_ids[] = $group;
1422
				else $group_names[] = $group;
1423
			}
1424
			$or_where_in = (!empty($group_ids) && !empty($group_names)) ? 'or_where_in' : 'where_in';
1425
			// if group name was used we do one more join with groups
1426
			if(!empty($group_names))
1427
			{
1428
				$this->db->join($this->tables['groups'], $this->tables['users_groups'] . '.' . $this->join['groups'] . ' = ' . $this->tables['groups'] . '.id', 'inner');
1429
				$this->db->where_in($this->tables['groups'] . '.name', $group_names);
1430
			}
1431
			if(!empty($group_ids))
1432
			{
1433
				$this->db->{$or_where_in}($this->tables['users_groups'].'.'.$this->join['groups'], $group_ids);
1434
			}
1435
		}
1436
1437
		$this->trigger_events('extra_where');
1438
1439
		// run each where that was passed
1440 View Code Duplication
		if (isset($this->_ion_where) && !empty($this->_ion_where))
1441
		{
1442
			foreach ($this->_ion_where as $where)
1443
			{
1444
				$this->db->where($where);
1445
			}
1446
1447
			$this->_ion_where = array();
1448
		}
1449
1450
		if (isset($this->_ion_like) && !empty($this->_ion_like))
1451
		{
1452
			foreach ($this->_ion_like as $like)
1453
			{
1454
				$this->db->or_like($like['like'], $like['value'], $like['position']);
1455
			}
1456
1457
			$this->_ion_like = array();
1458
		}
1459
1460 View Code Duplication
		if (isset($this->_ion_limit) && isset($this->_ion_offset))
1461
		{
1462
			$this->db->limit($this->_ion_limit, $this->_ion_offset);
1463
1464
			$this->_ion_limit  = NULL;
1465
			$this->_ion_offset = NULL;
1466
		}
1467
		else if (isset($this->_ion_limit))
1468
		{
1469
			$this->db->limit($this->_ion_limit);
1470
1471
			$this->_ion_limit  = NULL;
1472
		}
1473
1474
		// set the order
1475
		if (isset($this->_ion_order_by) && isset($this->_ion_order))
1476
		{
1477
			$this->db->order_by($this->_ion_order_by, $this->_ion_order);
1478
1479
			$this->_ion_order    = NULL;
1480
			$this->_ion_order_by = NULL;
1481
		}
1482
1483
		$this->response = $this->db->get($this->tables['users']);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->db->get($this->tables['users']) of type object<CI_DB_result> is incompatible with the declared type string of property $response.

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...
1484
1485
		return $this;
1486
	}
1487
1488
	/**
1489
	 * user
1490
	 *
1491
	 * @return object
1492
	 * @author Ben Edmunds
1493
	 **/
1494
	public function user($id = NULL)
1495
	{
1496
		$this->trigger_events('user');
1497
1498
		// if no id was passed use the current users id
1499
		$id = isset($id) ? $id : $this->session->userdata('user_id');
1500
1501
		$this->limit(1);
1502
		$this->order_by($this->tables['users'].'.id', 'desc');
1503
		$this->where($this->tables['users'].'.id', $id);
1504
1505
		$this->users();
1506
1507
		return $this;
1508
	}
1509
1510
	/**
1511
	 * get_users_groups
1512
	 *
1513
	 * @return array
1514
	 * @author Ben Edmunds
1515
	 **/
1516
	public function get_users_groups($id=FALSE)
1517
	{
1518
		$this->trigger_events('get_users_group');
1519
1520
		// if no id was passed use the current users id
1521
		$id || $id = $this->session->userdata('user_id');
1522
1523
		return $this->db->select($this->tables['users_groups'].'.'.$this->join['groups'].' as id, '.$this->tables['groups'].'.name, '.$this->tables['groups'].'.description')
1524
		                ->where($this->tables['users_groups'].'.'.$this->join['users'], $id)
1525
		                ->join($this->tables['groups'], $this->tables['users_groups'].'.'.$this->join['groups'].'='.$this->tables['groups'].'.id')
1526
		                ->get($this->tables['users_groups']);
1527
	}
1528
1529
	/**
1530
	 * add_to_group
1531
	 *
1532
	 * @return bool
1533
	 * @author Ben Edmunds
1534
	 **/
1535
	public function add_to_group($group_ids, $user_id=false)
1536
	{
1537
		$this->trigger_events('add_to_group');
1538
1539
		// if no id was passed use the current users id
1540
		$user_id || $user_id = $this->session->userdata('user_id');
1541
1542
		if(!is_array($group_ids))
1543
		{
1544
			$group_ids = array($group_ids);
1545
		}
1546
1547
		$return = 0;
1548
1549
		// Then insert each into the database
1550
		foreach ($group_ids as $group_id)
1551
		{
1552
			if ($this->db->insert($this->tables['users_groups'], array( $this->join['groups'] => (float)$group_id, $this->join['users'] => (float)$user_id)))
1553
			{
1554
				if (isset($this->_cache_groups[$group_id])) {
1555
					$group_name = $this->_cache_groups[$group_id];
1556
				}
1557
				else {
1558
					$group = $this->group($group_id)->result();
1559
					$group_name = $group[0]->name;
1560
					$this->_cache_groups[$group_id] = $group_name;
1561
				}
1562
				$this->_cache_user_in_group[$user_id][$group_id] = $group_name;
1563
1564
				// Return the number of groups added
1565
				$return += 1;
1566
			}
1567
		}
1568
1569
		return $return;
1570
	}
1571
1572
	/**
1573
	 * remove_from_group
1574
	 *
1575
	 * @return bool
1576
	 * @author Ben Edmunds
1577
	 **/
1578
	public function remove_from_group($group_ids=false, $user_id=false)
1579
	{
1580
		$this->trigger_events('remove_from_group');
1581
1582
		// user id is required
1583
		if(empty($user_id))
1584
		{
1585
			return FALSE;
1586
		}
1587
1588
		// if group id(s) are passed remove user from the group(s)
1589
		if( ! empty($group_ids))
1590
		{
1591
			if(!is_array($group_ids))
1592
			{
1593
				$group_ids = array($group_ids);
1594
			}
1595
1596
			foreach($group_ids as $group_id)
1597
			{
1598
				$this->db->delete($this->tables['users_groups'], array($this->join['groups'] => (float)$group_id, $this->join['users'] => (float)$user_id));
0 ignored issues
show
Documentation introduced by
array($this->join['group...] => (double) $user_id) is of type array<?,double>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1599
				if (isset($this->_cache_user_in_group[$user_id]) && isset($this->_cache_user_in_group[$user_id][$group_id]))
1600
				{
1601
					unset($this->_cache_user_in_group[$user_id][$group_id]);
1602
				}
1603
			}
1604
1605
			$return = TRUE;
1606
		}
1607
		// otherwise remove user from all groups
1608
		else
1609
		{
1610
			if ($return = $this->db->delete($this->tables['users_groups'], array($this->join['users'] => (float)$user_id))) {
0 ignored issues
show
Documentation introduced by
array($this->join['users'] => (double) $user_id) is of type array<?,double>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1611
				$this->_cache_user_in_group[$user_id] = array();
1612
			}
1613
		}
1614
		return $return;
1615
	}
1616
1617
	/**
1618
	 * groups
1619
	 *
1620
	 * @return object
1621
	 * @author Ben Edmunds
1622
	 **/
1623
	public function groups()
1624
	{
1625
		$this->trigger_events('groups');
1626
1627
		// run each where that was passed
1628 View Code Duplication
		if (isset($this->_ion_where) && !empty($this->_ion_where))
1629
		{
1630
			foreach ($this->_ion_where as $where)
1631
			{
1632
				$this->db->where($where);
1633
			}
1634
			$this->_ion_where = array();
1635
		}
1636
1637 View Code Duplication
		if (isset($this->_ion_limit) && isset($this->_ion_offset))
1638
		{
1639
			$this->db->limit($this->_ion_limit, $this->_ion_offset);
1640
1641
			$this->_ion_limit  = NULL;
1642
			$this->_ion_offset = NULL;
1643
		}
1644
		else if (isset($this->_ion_limit))
1645
		{
1646
			$this->db->limit($this->_ion_limit);
1647
1648
			$this->_ion_limit  = NULL;
1649
		}
1650
1651
		// set the order
1652
		if (isset($this->_ion_order_by) && isset($this->_ion_order))
1653
		{
1654
			$this->db->order_by($this->_ion_order_by, $this->_ion_order);
1655
		}
1656
1657
		$this->response = $this->db->get($this->tables['groups']);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->db->get($this->tables['groups']) of type object<CI_DB_result> is incompatible with the declared type string of property $response.

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...
1658
1659
		return $this;
1660
	}
1661
1662
	/**
1663
	 * group
1664
	 *
1665
	 * @return object
1666
	 * @author Ben Edmunds
1667
	 **/
1668
	public function group($id = NULL)
1669
	{
1670
		$this->trigger_events('group');
1671
1672
		if (isset($id))
1673
		{
1674
			$this->where($this->tables['groups'].'.id', $id);
1675
		}
1676
1677
		$this->limit(1);
1678
		$this->order_by('id', 'desc');
1679
1680
		return $this->groups();
1681
	}
1682
1683
	/**
1684
	 * update
1685
	 *
1686
	 * @return bool
1687
	 * @author Phil Sturgeon
1688
	 **/
1689
	public function update($id, array $data)
1690
	{
1691
		$this->trigger_events('pre_update_user');
1692
1693
		$user = $this->user($id)->row();
1694
1695
		$this->db->trans_begin();
1696
1697
		if (array_key_exists($this->identity_column, $data) && $this->identity_check($data[$this->identity_column]) && $user->{$this->identity_column} !== $data[$this->identity_column])
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1698
		{
1699
			$this->db->trans_rollback();
1700
			$this->set_error('account_creation_duplicate_identity');
1701
1702
			$this->trigger_events(array('post_update_user', 'post_update_user_unsuccessful'));
1703
			$this->set_error('update_unsuccessful');
1704
1705
			return FALSE;
1706
		}
1707
1708
		// Filter the data passed
1709
		$data = $this->_filter_data($this->tables['users'], $data);
1710
1711
		if (array_key_exists($this->identity_column, $data) || array_key_exists('password', $data) || array_key_exists('email', $data))
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1712
		{
1713
			if (array_key_exists('password', $data))
1714
			{
1715
				if( ! empty($data['password']))
1716
				{
1717
					$data['password'] = $this->hash_password($data['password'], $user->salt);
1718
				}
1719
				else
1720
				{
1721
					// unset password so it doesn't effect database entry if no password passed
1722
					unset($data['password']);
1723
				}
1724
			}
1725
		}
1726
1727
		$this->trigger_events('extra_where');
1728
		$this->db->update($this->tables['users'], $data, array('id' => $user->id));
1729
1730 View Code Duplication
		if ($this->db->trans_status() === FALSE)
1731
		{
1732
			$this->db->trans_rollback();
1733
1734
			$this->trigger_events(array('post_update_user', 'post_update_user_unsuccessful'));
1735
			$this->set_error('update_unsuccessful');
1736
			return FALSE;
1737
		}
1738
1739
		$this->db->trans_commit();
1740
1741
		$this->trigger_events(array('post_update_user', 'post_update_user_successful'));
1742
		$this->set_message('update_successful');
1743
		return TRUE;
1744
	}
1745
1746
	/**
1747
	* delete_user
1748
	*
1749
	* @return bool
1750
	* @author Phil Sturgeon
1751
	**/
1752
	public function delete_user($id)
1753
	{
1754
		$this->trigger_events('pre_delete_user');
1755
1756
		$this->db->trans_begin();
1757
1758
		// remove user from groups
1759
		$this->remove_from_group(NULL, $id);
0 ignored issues
show
Documentation introduced by
NULL is of type null, but the function expects a boolean.

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...
1760
1761
		// delete user from users table should be placed after remove from group
1762
		$this->db->delete($this->tables['users'], array('id' => $id));
0 ignored issues
show
Documentation introduced by
array('id' => $id) is of type array<string,?,{"id":"?"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1763
1764
1765 View Code Duplication
		if ($this->db->trans_status() === FALSE)
1766
		{
1767
			$this->db->trans_rollback();
1768
			$this->trigger_events(array('post_delete_user', 'post_delete_user_unsuccessful'));
1769
			$this->set_error('delete_unsuccessful');
1770
			return FALSE;
1771
		}
1772
1773
		$this->db->trans_commit();
1774
1775
		$this->trigger_events(array('post_delete_user', 'post_delete_user_successful'));
1776
		$this->set_message('delete_successful');
1777
		return TRUE;
1778
	}
1779
1780
	/**
1781
	 * update_last_login
1782
	 *
1783
	 * @return bool
1784
	 * @author Ben Edmunds
1785
	 **/
1786
	public function update_last_login($id)
1787
	{
1788
		$this->trigger_events('update_last_login');
1789
1790
		$this->load->helper('date');
1791
1792
		$this->trigger_events('extra_where');
1793
1794
		$this->db->update($this->tables['users'], array('last_login' => time()), array('id' => $id));
1795
1796
		return $this->db->affected_rows() == 1;
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class CI_DB_query_builder as the method affected_rows() does only exist in the following sub-classes of CI_DB_query_builder: CI_DB_cubrid_driver, CI_DB_ibase_driver, CI_DB_mssql_driver, CI_DB_mysql_driver, CI_DB_mysqli_driver, CI_DB_oci8_driver, CI_DB_pdo_4d_driver, CI_DB_pdo_cubrid_driver, CI_DB_pdo_dblib_driver, CI_DB_pdo_driver, CI_DB_pdo_firebird_driver, CI_DB_pdo_ibm_driver, CI_DB_pdo_informix_driver, CI_DB_pdo_mysql_driver, CI_DB_pdo_oci_driver, CI_DB_pdo_odbc_driver, CI_DB_pdo_pgsql_driver, CI_DB_pdo_sqlite_driver, CI_DB_pdo_sqlsrv_driver, CI_DB_postgre_driver, CI_DB_sqlite3_driver, CI_DB_sqlite_driver, CI_DB_sqlsrv_driver. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
1797
	}
1798
1799
	/**
1800
	 * set_lang
1801
	 *
1802
	 * @return bool
1803
	 * @author Ben Edmunds
1804
	 **/
1805
	public function set_lang($lang = 'en')
1806
	{
1807
		$this->trigger_events('set_lang');
1808
1809
		// if the user_expire is set to zero we'll set the expiration two years from now.
1810 View Code Duplication
		if($this->config->item('user_expire', 'ion_auth') === 0)
1811
		{
1812
			$expire = (60*60*24*365*2);
1813
		}
1814
		// otherwise use what is set
1815
		else
1816
		{
1817
			$expire = $this->config->item('user_expire', 'ion_auth');
1818
		}
1819
1820
		set_cookie(array(
1821
			'name'   => 'lang_code',
1822
			'value'  => $lang,
1823
			'expire' => $expire
1824
		));
1825
1826
		return TRUE;
1827
	}
1828
1829
	/**
1830
	 * set_session
1831
	 *
1832
	 * @return bool
1833
	 * @author jrmadsen67
1834
	 **/
1835
	public function set_session($user)
1836
	{
1837
1838
		$this->trigger_events('pre_set_session');
1839
1840
		$session_data = array(
1841
		    'identity'             => $user->{$this->identity_column},
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1842
		    $this->identity_column             => $user->{$this->identity_column},
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1843
		    'email'                => $user->email,
1844
		    'user_id'              => $user->id, //everyone likes to overwrite id so we'll use user_id
1845
		    'old_last_login'       => $user->last_login,
1846
		    'last_check'           => time(),
1847
		);
1848
1849
		$this->session->set_userdata($session_data);
1850
1851
		$this->trigger_events('post_set_session');
1852
1853
		return TRUE;
1854
	}
1855
1856
	/**
1857
	 * remember_user
1858
	 *
1859
	 * @return bool
1860
	 * @author Ben Edmunds
1861
	 **/
1862
	public function remember_user($id)
1863
	{
1864
		$this->trigger_events('pre_remember_user');
1865
1866
		if (!$id)
1867
		{
1868
			return FALSE;
1869
		}
1870
1871
		$user = $this->user($id)->row();
1872
1873
		$salt = $this->salt();
1874
1875
		$this->db->update($this->tables['users'], array('remember_code' => $salt), array('id' => $id));
1876
1877
		if ($this->db->affected_rows() > -1)
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class CI_DB_query_builder as the method affected_rows() does only exist in the following sub-classes of CI_DB_query_builder: CI_DB_cubrid_driver, CI_DB_ibase_driver, CI_DB_mssql_driver, CI_DB_mysql_driver, CI_DB_mysqli_driver, CI_DB_oci8_driver, CI_DB_pdo_4d_driver, CI_DB_pdo_cubrid_driver, CI_DB_pdo_dblib_driver, CI_DB_pdo_driver, CI_DB_pdo_firebird_driver, CI_DB_pdo_ibm_driver, CI_DB_pdo_informix_driver, CI_DB_pdo_mysql_driver, CI_DB_pdo_oci_driver, CI_DB_pdo_odbc_driver, CI_DB_pdo_pgsql_driver, CI_DB_pdo_sqlite_driver, CI_DB_pdo_sqlsrv_driver, CI_DB_postgre_driver, CI_DB_sqlite3_driver, CI_DB_sqlite_driver, CI_DB_sqlsrv_driver. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
1878
		{
1879
			// if the user_expire is set to zero we'll set the expiration two years from now.
1880 View Code Duplication
			if($this->config->item('user_expire', 'ion_auth') === 0)
1881
			{
1882
				$expire = (60*60*24*365*2);
1883
			}
1884
			// otherwise use what is set
1885
			else
1886
			{
1887
				$expire = $this->config->item('user_expire', 'ion_auth');
1888
			}
1889
1890
			set_cookie(array(
1891
			    'name'   => $this->config->item('identity_cookie_name', 'ion_auth'),
1892
			    'value'  => $user->{$this->identity_column},
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1893
			    'expire' => $expire
1894
			));
1895
1896
			set_cookie(array(
1897
			    'name'   => $this->config->item('remember_cookie_name', 'ion_auth'),
1898
			    'value'  => $salt,
1899
			    'expire' => $expire
1900
			));
1901
1902
			$this->trigger_events(array('post_remember_user', 'remember_user_successful'));
1903
			return TRUE;
1904
		}
1905
1906
		$this->trigger_events(array('post_remember_user', 'remember_user_unsuccessful'));
1907
		return FALSE;
1908
	}
1909
1910
	/**
1911
	 * login_remembed_user
1912
	 *
1913
	 * @return bool
1914
	 * @author Ben Edmunds
1915
	 **/
1916
	public function login_remembered_user()
1917
	{
1918
		$this->trigger_events('pre_login_remembered_user');
1919
1920
		// check for valid data
1921
		if (!get_cookie($this->config->item('identity_cookie_name', 'ion_auth'))
1922
			|| !get_cookie($this->config->item('remember_cookie_name', 'ion_auth'))
1923
			|| !$this->identity_check(get_cookie($this->config->item('identity_cookie_name', 'ion_auth'))))
1924
		{
1925
			$this->trigger_events(array('post_login_remembered_user', 'post_login_remembered_user_unsuccessful'));
1926
			return FALSE;
1927
		}
1928
1929
		// get the user
1930
		$this->trigger_events('extra_where');
1931
		$query = $this->db->select($this->identity_column.', id, email, last_login')
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1932
		                  ->where($this->identity_column, urldecode(get_cookie($this->config->item('identity_cookie_name', 'ion_auth'))))
0 ignored issues
show
Bug introduced by
The property identity_column does not seem to exist. Did you mean identity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1933
		                  ->where('remember_code', get_cookie($this->config->item('remember_cookie_name', 'ion_auth')))
1934
				  ->where('active',1)
1935
		                  ->limit(1)
1936
		    			  ->order_by('id', 'desc')
1937
		                  ->get($this->tables['users']);
1938
1939
		// if the user was found, sign them in
1940
		if ($query->num_rows() == 1)
1941
		{
1942
			$user = $query->row();
1943
1944
			$this->update_last_login($user->id);
1945
1946
			$this->set_session($user);
1947
1948
			// extend the users cookies if the option is enabled
1949
			if ($this->config->item('user_extend_on_login', 'ion_auth'))
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->config->item('use..._on_login', 'ion_auth') of type string|null is loosely compared to true; this is ambiguous if the string can be empty. 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 string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1950
			{
1951
				$this->remember_user($user->id);
1952
			}
1953
1954
			$this->trigger_events(array('post_login_remembered_user', 'post_login_remembered_user_successful'));
1955
			return TRUE;
1956
		}
1957
1958
		$this->trigger_events(array('post_login_remembered_user', 'post_login_remembered_user_unsuccessful'));
1959
		return FALSE;
1960
	}
1961
1962
1963
	/**
1964
	 * create_group
1965
	 *
1966
	 * @author aditya menon
1967
	*/
1968
	public function create_group($group_name = FALSE, $group_description = '', $additional_data = array())
1969
	{
1970
		// bail if the group name was not passed
1971
		if(!$group_name)
1972
		{
1973
			$this->set_error('group_name_required');
1974
			return FALSE;
1975
		}
1976
1977
		// bail if the group name already exists
1978
		$existing_group = $this->db->get_where($this->tables['groups'], array('name' => $group_name))->num_rows();
0 ignored issues
show
Documentation introduced by
array('name' => $group_name) is of type array<string,boolean,{"name":"boolean"}>, 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...
1979
		if($existing_group !== 0)
1980
		{
1981
			$this->set_error('group_already_exists');
1982
			return FALSE;
1983
		}
1984
1985
		$data = array('name'=>$group_name,'description'=>$group_description);
1986
1987
		// filter out any data passed that doesnt have a matching column in the groups table
1988
		// and merge the set group data and the additional data
1989 View Code Duplication
		if (!empty($additional_data)) $data = array_merge($this->_filter_data($this->tables['groups'], $additional_data), $data);
1990
1991
		$this->trigger_events('extra_group_set');
1992
1993
		// insert the new group
1994
		$this->db->insert($this->tables['groups'], $data);
1995
		$group_id = $this->db->insert_id($this->tables['groups'] . '_id_seq');
0 ignored issues
show
Bug introduced by
The method insert_id() does not exist on CI_DB_query_builder. Did you maybe mean insert()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1996
1997
		// report success
1998
		$this->set_message('group_creation_successful');
1999
		// return the brand new group id
2000
		return $group_id;
2001
	}
2002
2003
	/**
2004
	 * update_group
2005
	 *
2006
	 * @return bool
2007
	 * @author aditya menon
2008
	 **/
2009
	public function update_group($group_id = FALSE, $group_name = FALSE, $additional_data = array())
2010
	{
2011
		if (empty($group_id)) return FALSE;
2012
2013
		$data = array();
2014
2015
		if (!empty($group_name))
2016
		{
2017
			// we are changing the name, so do some checks
2018
2019
			// bail if the group name already exists
2020
			$existing_group = $this->db->get_where($this->tables['groups'], array('name' => $group_name))->row();
0 ignored issues
show
Documentation introduced by
array('name' => $group_name) is of type array<string,boolean,{"name":"boolean"}>, 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...
2021
			if(isset($existing_group->id) && $existing_group->id != $group_id)
2022
			{
2023
				$this->set_error('group_already_exists');
2024
				return FALSE;
2025
			}
2026
2027
			$data['name'] = $group_name;
2028
		}
2029
2030
		// restrict change of name of the admin group
2031
        $group = $this->db->get_where($this->tables['groups'], array('id' => $group_id))->row();
0 ignored issues
show
Documentation introduced by
array('id' => $group_id) is of type array<string,boolean,{"id":"boolean"}>, 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...
2032
        if($this->config->item('admin_group', 'ion_auth') === $group->name && $group_name !== $group->name)
2033
        {
2034
            $this->set_error('group_name_admin_not_alter');
2035
            return FALSE;
2036
        }
2037
2038
2039
		// IMPORTANT!! Third parameter was string type $description; this following code is to maintain backward compatibility
2040
		// New projects should work with 3rd param as array
2041
		if (is_string($additional_data)) $additional_data = array('description' => $additional_data);
2042
2043
2044
		// filter out any data passed that doesnt have a matching column in the groups table
2045
		// and merge the set group data and the additional data
2046 View Code Duplication
		if (!empty($additional_data)) $data = array_merge($this->_filter_data($this->tables['groups'], $additional_data), $data);
2047
2048
2049
		$this->db->update($this->tables['groups'], $data, array('id' => $group_id));
2050
2051
		$this->set_message('group_update_successful');
2052
2053
		return TRUE;
2054
	}
2055
2056
	/**
2057
	* delete_group
2058
	*
2059
	* @return bool
2060
	* @author aditya menon
2061
	**/
2062
	public function delete_group($group_id = FALSE)
2063
	{
2064
		// bail if mandatory param not set
2065
		if(!$group_id || empty($group_id))
2066
		{
2067
			return FALSE;
2068
		}
2069
		$group = $this->group($group_id)->row();
2070
		if($group->name == $this->config->item('admin_group', 'ion_auth'))
2071
		{
2072
			$this->trigger_events(array('post_delete_group', 'post_delete_group_notallowed'));
2073
			$this->set_error('group_delete_notallowed');
2074
			return FALSE;
2075
		}
2076
2077
		$this->trigger_events('pre_delete_group');
2078
2079
		$this->db->trans_begin();
2080
2081
		// remove all users from this group
2082
		$this->db->delete($this->tables['users_groups'], array($this->join['groups'] => $group_id));
0 ignored issues
show
Documentation introduced by
array($this->join['groups'] => $group_id) is of type array<?,boolean>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
2083
		// remove the group itself
2084
		$this->db->delete($this->tables['groups'], array('id' => $group_id));
0 ignored issues
show
Documentation introduced by
array('id' => $group_id) is of type array<string,boolean,{"id":"boolean"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
2085
2086 View Code Duplication
		if ($this->db->trans_status() === FALSE)
2087
		{
2088
			$this->db->trans_rollback();
2089
			$this->trigger_events(array('post_delete_group', 'post_delete_group_unsuccessful'));
2090
			$this->set_error('group_delete_unsuccessful');
2091
			return FALSE;
2092
		}
2093
2094
		$this->db->trans_commit();
2095
2096
		$this->trigger_events(array('post_delete_group', 'post_delete_group_successful'));
2097
		$this->set_message('group_delete_successful');
2098
		return TRUE;
2099
	}
2100
2101
	public function set_hook($event, $name, $class, $method, $arguments)
2102
	{
2103
		$this->_ion_hooks->{$event}[$name] = new stdClass;
2104
		$this->_ion_hooks->{$event}[$name]->class     = $class;
2105
		$this->_ion_hooks->{$event}[$name]->method    = $method;
2106
		$this->_ion_hooks->{$event}[$name]->arguments = $arguments;
2107
	}
2108
2109
	public function remove_hook($event, $name)
2110
	{
2111
		if (isset($this->_ion_hooks->{$event}[$name]))
2112
		{
2113
			unset($this->_ion_hooks->{$event}[$name]);
2114
		}
2115
	}
2116
2117
	public function remove_hooks($event)
2118
	{
2119
		if (isset($this->_ion_hooks->$event))
2120
		{
2121
			unset($this->_ion_hooks->$event);
2122
		}
2123
	}
2124
2125
	protected function _call_hook($event, $name)
2126
	{
2127
		if (isset($this->_ion_hooks->{$event}[$name]) && method_exists($this->_ion_hooks->{$event}[$name]->class, $this->_ion_hooks->{$event}[$name]->method))
2128
		{
2129
			$hook = $this->_ion_hooks->{$event}[$name];
2130
2131
			return call_user_func_array(array($hook->class, $hook->method), $hook->arguments);
2132
		}
2133
2134
		return FALSE;
2135
	}
2136
2137
	public function trigger_events($events)
2138
	{
2139
		if (is_array($events) && !empty($events))
2140
		{
2141
			foreach ($events as $event)
2142
			{
2143
				$this->trigger_events($event);
2144
			}
2145
		}
2146
		else
2147
		{
2148
			if (isset($this->_ion_hooks->$events) && !empty($this->_ion_hooks->$events))
2149
			{
2150
				foreach ($this->_ion_hooks->$events as $name => $hook)
2151
				{
2152
					$this->_call_hook($events, $name);
2153
				}
2154
			}
2155
		}
2156
	}
2157
2158
	/**
2159
	 * set_message_delimiters
2160
	 *
2161
	 * Set the message delimiters
2162
	 *
2163
	 * @return void
2164
	 * @author Ben Edmunds
2165
	 **/
2166
	public function set_message_delimiters($start_delimiter, $end_delimiter)
2167
	{
2168
		$this->message_start_delimiter = $start_delimiter;
0 ignored issues
show
Bug introduced by
The property message_start_delimiter does not seem to exist. Did you mean limiter?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
2169
		$this->message_end_delimiter   = $end_delimiter;
0 ignored issues
show
Bug introduced by
The property message_end_delimiter does not seem to exist. Did you mean limiter?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
2170
2171
		return TRUE;
2172
	}
2173
2174
	/**
2175
	 * set_error_delimiters
2176
	 *
2177
	 * Set the error delimiters
2178
	 *
2179
	 * @return void
2180
	 * @author Ben Edmunds
2181
	 **/
2182
	public function set_error_delimiters($start_delimiter, $end_delimiter)
2183
	{
2184
		$this->error_start_delimiter = $start_delimiter;
2185
		$this->error_end_delimiter   = $end_delimiter;
2186
2187
		return TRUE;
2188
	}
2189
2190
	/**
2191
	 * set_message
2192
	 *
2193
	 * Set a message
2194
	 *
2195
	 * @return void
2196
	 * @author Ben Edmunds
2197
	 **/
2198
	public function set_message($message)
2199
	{
2200
		$this->messages[] = $message;
2201
2202
		return $message;
2203
	}
2204
2205
2206
2207
	/**
2208
	 * messages
2209
	 *
2210
	 * Get the messages
2211
	 *
2212
	 * @return void
2213
	 * @author Ben Edmunds
2214
	 **/
2215
	public function messages()
2216
	{
2217
		$_output = '';
2218 View Code Duplication
		foreach ($this->messages as $message)
0 ignored issues
show
Bug introduced by
The expression $this->messages of type string is not traversable.
Loading history...
2219
		{
2220
			$messageLang = $this->lang->line($message) ? $this->lang->line($message) : '##' . $message . '##';
2221
			$_output .= $this->message_start_delimiter . $messageLang . $this->message_end_delimiter;
0 ignored issues
show
Bug introduced by
The property message_start_delimiter does not seem to exist. Did you mean limiter?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
Bug introduced by
The property message_end_delimiter does not seem to exist. Did you mean limiter?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
2222
		}
2223
2224
		return $_output;
2225
	}
2226
2227
	/**
2228
	 * messages as array
2229
	 *
2230
	 * Get the messages as an array
2231
	 *
2232
	 * @return array
2233
	 * @author Raul Baldner Junior
2234
	 **/
2235
	public function messages_array($langify = TRUE)
2236
	{
2237
		if ($langify)
2238
		{
2239
			$_output = array();
2240 View Code Duplication
			foreach ($this->messages as $message)
0 ignored issues
show
Bug introduced by
The expression $this->messages of type string is not traversable.
Loading history...
2241
			{
2242
				$messageLang = $this->lang->line($message) ? $this->lang->line($message) : '##' . $message . '##';
2243
				$_output[] = $this->message_start_delimiter . $messageLang . $this->message_end_delimiter;
0 ignored issues
show
Bug introduced by
The property message_start_delimiter does not seem to exist. Did you mean limiter?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
Bug introduced by
The property message_end_delimiter does not seem to exist. Did you mean limiter?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
2244
			}
2245
			return $_output;
2246
		}
2247
		else
2248
		{
2249
			return $this->messages;
2250
		}
2251
	}
2252
2253
2254
	/**
2255
	 * clear_messages
2256
	 *
2257
	 * Clear messages
2258
	 *
2259
	 * @return void
2260
	 * @author Ben Edmunds
2261
	 **/
2262
	public function clear_messages()
2263
	{
2264
		$this->messages = array();
0 ignored issues
show
Documentation Bug introduced by
It seems like array() of type array is incompatible with the declared type string of property $messages.

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...
2265
2266
		return TRUE;
2267
	}
2268
2269
2270
	/**
2271
	 * set_error
2272
	 *
2273
	 * Set an error message
2274
	 *
2275
	 * @return void
2276
	 * @author Ben Edmunds
2277
	 **/
2278
	public function set_error($error)
2279
	{
2280
		$this->errors[] = $error;
2281
2282
		return $error;
2283
	}
2284
2285
	/**
2286
	 * errors
2287
	 *
2288
	 * Get the error message
2289
	 *
2290
	 * @return void
2291
	 * @author Ben Edmunds
2292
	 **/
2293
	public function errors()
2294
	{
2295
		$_output = '';
2296 View Code Duplication
		foreach ($this->errors as $error)
0 ignored issues
show
Bug introduced by
The expression $this->errors of type string is not traversable.
Loading history...
2297
		{
2298
			$errorLang = $this->lang->line($error) ? $this->lang->line($error) : '##' . $error . '##';
2299
			$_output .= $this->error_start_delimiter . $errorLang . $this->error_end_delimiter;
2300
		}
2301
2302
		return $_output;
2303
	}
2304
2305
	/**
2306
	 * errors as array
2307
	 *
2308
	 * Get the error messages as an array
2309
	 *
2310
	 * @return array
2311
	 * @author Raul Baldner Junior
2312
	 **/
2313
	public function errors_array($langify = TRUE)
2314
	{
2315
		if ($langify)
2316
		{
2317
			$_output = array();
2318 View Code Duplication
			foreach ($this->errors as $error)
0 ignored issues
show
Bug introduced by
The expression $this->errors of type string is not traversable.
Loading history...
2319
			{
2320
				$errorLang = $this->lang->line($error) ? $this->lang->line($error) : '##' . $error . '##';
2321
				$_output[] = $this->error_start_delimiter . $errorLang . $this->error_end_delimiter;
2322
			}
2323
			return $_output;
2324
		}
2325
		else
2326
		{
2327
			return $this->errors;
2328
		}
2329
	}
2330
2331
2332
	/**
2333
	 * clear_errors
2334
	 *
2335
	 * Clear Errors
2336
	 *
2337
	 * @return void
2338
	 * @author Ben Edmunds
2339
	 **/
2340
	public function clear_errors()
2341
	{
2342
		$this->errors = array();
0 ignored issues
show
Documentation Bug introduced by
It seems like array() of type array is incompatible with the declared type string of property $errors.

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...
2343
2344
		return TRUE;
2345
	}
2346
2347
2348
2349
	protected function _filter_data($table, $data)
2350
	{
2351
		$filtered_data = array();
2352
		$columns = $this->db->list_fields($table);
2353
2354
		if (is_array($data))
2355
		{
2356
			foreach ($columns as $column)
2357
			{
2358
				if (array_key_exists($column, $data))
2359
					$filtered_data[$column] = $data[$column];
2360
			}
2361
		}
2362
2363
		return $filtered_data;
2364
	}
2365
2366
	protected function _prepare_ip($ip_address) {
2367
		// just return the string IP address now for better compatibility
2368
		return $ip_address;
2369
	}
2370
}
2371