Completed
Push — development ( 86ad30...7b6aa4 )
by Sebastian
05:00
created

include/classes/user.class.php (9 issues)

Upgrade to new PHP Analysis Engine

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

1
<?php
2
$defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1;
3
4
class User extends Base {
5
  protected $table = 'accounts';
6
  private $userID = false;
7
  private $user = array();
8
9
  /**
10
   * We allow changing the database for shared accounts across pools
11
   * Load the config on construct so we can assign the DB name
12
   * @param config array MPOS configuration
13
   * @return none
14
   **/
15
  public function __construct($config) {
16
    $this->setConfig($config);
17
    $this->table = $this->config['db']['shared']['accounts'] . '.' . $this->table;
18
  }
19
20
  // get and set methods
21
  private function getHash($string, $version=0, $pepper='') {
22
    switch($version) {
23
    case 0:
24
      return hash('sha256', $string.$this->salt);
25
      break;
26
    case 1:
27
      return '$' . $version . '$' . $pepper . '$' . hash('sha256', $string.$this->salt.$pepper);
28
      break;
29
    }
30
  }
31
  public function getUserName($id) {
32
    return $this->getSingle($id, 'username', 'id');
33
  }
34
  public function getUserNameAnon($id) {
35
    return $this->getSingle($id, 'is_anonymous', 'id');
36
  }
37
  public function getUserNameByEmail($email) {
38
    return $this->getSingle($email, 'username', 'email', 's');
39
  }
40
  public function getUserId($username, $lower=false) {
41
    return $this->getSingle($username, 'id', 'username', 's', $lower);
42
  }
43
  public function getUserIdByEmail($email, $lower=false) {
44
    return $this->getSingle($email, 'id', 'email', 's', $lower);
45
  }
46
  public function getUserEmail($username, $lower=false) {
47
    return $this->getSingle($username, 'email', 'username', 's', $lower);
48
  }
49
  public function getUserEmailById($id) {
50
    return $this->getSingle($id, 'email', 'id', 'i');
51
  }
52
  public function getUserPasswordHashById($id) {
53
    return $this->getSingle($id, 'pass', 'id', 'i');
54
  }
55
  public function getUserPinHashById($id) {
56
    return $this->getSingle($id, 'pin', 'id', 'i');
57
  }
58
  public function getUserNoFee($id) {
59
    return $this->getSingle($id, 'no_fees', 'id');
60
  }
61
  public function getUserDonatePercent($id) {
62
    return $this->getDonatePercent($id);
63
  }
64
  public function getUserAdmin($id) {
65
    return $this->getSingle($id, 'is_admin', 'id');
66
  }
67
  public function getUserLocked($id) {
68
    return $this->getSingle($id, 'is_locked', 'id');
69
  }
70
  public function getUserIp($id) {
71
    return $this->getSingle($id, 'loggedIp', 'id');
72
  }
73
  public function getLastLogin($id) {
74
    return $this->getSingle($id, 'last_login', 'id');
75
  }
76
  public function getEmail($email) {
77
    return $this->getSingle($email, 'email', 'email', 's');
78
  }
79
  public function getUserFailed($id) {
80
   return $this->getSingle($id, 'failed_logins', 'id');
81
  }
82
  public function getUserPinFailed($id) {
83
   return $this->getSingle($id, 'failed_pins', 'id');
84
  }
85
  public function isNoFee($id) {
86
    return $this->getUserNoFee($id);
87
  }
88
  public function isLocked($id) {
89
    return $this->getUserLocked($id);
90
  }
91
  public function isAdmin($id) {
92
    return $this->getUserAdmin($id);
93
  }
94
  public function getSignupTime($id) {
95
    return $this->getSingle($id, 'signup_timestamp', 'id');
96
  }
97
  public function changeNoFee($id) {
98
    $field = array('name' => 'no_fees', 'type' => 'i', 'value' => !$this->isNoFee($id));
99
    $this->log->log("warn", $this->getUserName($id)." changed no_fees to ".$this->isNoFee($id));
100
    return $this->updateSingle($id, $field);
101
  }
102
  public function setLocked($id, $value) {
103
    $field = array('name' => 'is_locked', 'type' => 'i', 'value' => $value);
104
    $this->log->log("warn", $this->getUserName($id)." changed is_locked to $value");
105
    return $this->updateSingle($id, $field);
106
  }
107
  public function changeAdmin($id) {
108
    $field = array('name' => 'is_admin', 'type' => 'i', 'value' => !$this->isAdmin($id));
109
    $this->log->log("warn", $this->getUserName($id)." changed is_admin to ".$this->isAdmin($id));
110
    return $this->updateSingle($id, $field);
111
  }
112
  public function setUserFailed($id, $value) {
113
    $field = array( 'name' => 'failed_logins', 'type' => 'i', 'value' => $value);
114
    return $this->updateSingle($id, $field);
115
  }
116
  public function setUserPinFailed($id, $value) {
117
    $field = array( 'name' => 'failed_pins', 'type' => 'i', 'value' => $value);
118
    return $this->updateSingle($id, $field);
119
  }
120
  private function incUserFailed($id) {
121
    $field = array( 'name' => 'failed_logins', 'type' => 'i', 'value' => $this->getUserFailed($id) + 1);
122
    return $this->updateSingle($id, $field);
123
  }
124
  private function incUserPinFailed($id) {
125
    $field = array( 'name' => 'failed_pins', 'type' => 'i', 'value' => $this->getUserPinFailed($id) + 1);
126
    return $this->updateSingle($id, $field);
127
  }
128
  private function setUserIp($id, $ip) {
129
    $field = array( 'name' => 'loggedIp', 'type' => 's', 'value' => $ip );
130
    return $this->updateSingle($id, $field);
131
  }
132
133
  /**
134
   * Fetch all users for administrative tasks
135
   * @param none
136
   * @return data array All users with db columns as array fields
137
   **/
138
  public function getUsers($filter='%') {
139
    $stmt = $this->mysqli->prepare("SELECT * FROM " . $this->getTableName() . " WHERE username LIKE ?");
140
    if ($this->checkStmt($stmt) && $stmt->bind_param('s', $filter) && $stmt->execute() && $result = $stmt->get_result()) {
141
      return $result->fetch_all(MYSQLI_ASSOC);
142
    }
143
  }
144
145
  /**
146
   * Fetch last registered users for administrative tasks
147
   * @param none
148
   * @return data array All users with db columns as array fields
149
   **/
150 View Code Duplication
  public function getLastRegisteredUsers($limit=10,$start=0) {
151
    $this->debug->append("STA " . __METHOD__, 4);
152
    $invitation = new Invitation();
153
    $invitation->setMysql($this->mysqli);
154
    $invitation->setDebug($this->debug);
155
    $invitation->setLog($this->log);
156
    $stmt = $this->mysqli->prepare("
157
    	SELECT a.id,a.username as mposuser,a.email,a.signup_timestamp,u.username AS inviter FROM " . $this->getTableName() . " AS a
158
    	LEFT JOIN " . $invitation->getTableName() . " AS i
159
    	ON a.email = i.email
160
    	LEFT JOIN " . $this->getTableName() . " AS u
161
    	ON i.account_id = u.id
162
    	ORDER BY a.id DESC LIMIT ?,?");
163
    if ($this->checkStmt($stmt) && $stmt->bind_param("ii", $start, $limit) && $stmt->execute() && $result = $stmt->get_result()) {
164
      return $result->fetch_all(MYSQLI_ASSOC);
165
    }
166
  }
167
168
  /**
169
   * Fetch Top 10 Inviters
170
   * @param none
171
   * @return data array All users with db columns as array fields
172
   **/
173 View Code Duplication
  public function getTopInviters($limit=10,$start=0) {
174
    $this->debug->append("STA " . __METHOD__, 4);
175
    $invitation = new Invitation();
176
    $invitation->setMysql($this->mysqli);
177
    $invitation->setDebug($this->debug);
178
    $invitation->setLog($this->log);
179
    $stmt = $this->mysqli->prepare("
180
    	SELECT COUNT(i.account_id) AS invitationcount,a.id,a.username,a.email,
181
    	(SELECT COUNT(account_id) FROM " . $invitation->getTableName() . " WHERE account_id = i.account_id AND is_activated = 1 GROUP BY account_id) AS activated
182
    	FROM " . $invitation->getTableName() . " AS i
183
    	LEFT JOIN " . $this->getTableName() . " AS a
184
    	ON a.id = i.account_id
185
    	GROUP BY i.account_id
186
    	ORDER BY invitationcount ASC
187
    	LIMIT ?,?");
188
    if ($this->checkStmt($stmt) && $stmt->bind_param("ii", $start, $limit) && $stmt->execute() && $result = $stmt->get_result()) {
189
      return $result->fetch_all(MYSQLI_ASSOC);
190
    }
191
  }
192
193
  /**
194
   * Check user login
195
   * @param username string Username
196
   * @param password string Password
197
   * @return bool
198
   **/
199
  public function checkLogin($username, $password) {
0 ignored issues
show
checkLogin uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
200
    $this->debug->append("STA " . __METHOD__, 4);
201
    $this->debug->append("Checking login for $username with password $password", 2);
202
    if (empty($username) || empty($password)) {
203
      $this->setErrorMessage("Invalid username or password.");
204
      return false;
205
    }
206
    if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
207
      $this->debug->append("Not an e-mail address, rejecting login", 2);
208
      $this->setErrorMessage("Please login with your e-mail address");
209
      return false;
210
    } else {
211
      $this->debug->append("Username is an e-mail: $username", 2);
212
      if (!$username = $this->getUserNameByEmail($username)) {
213
        $this->setErrorMessage("Invalid username or password.");
214
        return false;
215
      }
216
    }
217
    if ($this->isLocked($this->getUserId($username))) {
218
      $this->setErrorMessage('Account locked. Please Check your Email for instructions to unlock.');
219
      return false;
220
    }
221
    if ($this->checkUserPassword($username, $password)) {
222
      // delete notification cookies
223
      setcookie("motd-box", "", time()-3600);
224
      setcookie("lastlogin-box", "", time()-3600);
225
      setcookie("backend-box", "", time()-3600);
226
      // rest of login process
227
      $uid = $this->getUserId($username);
228
      $lastLoginTime = $this->getLastLogin($uid);
229
      $this->updateLoginTimestamp($uid);
230
      $getIPAddress = $this->getUserIp($uid);
231
      if ($getIPAddress !== $this->getCurrentIP()) {
232
        $this->log->log("warn", "$username has logged in with a different IP, saved is [$getIPAddress]");
233
      }
234
      $setIPAddress = $this->setUserIp($uid, $_SERVER['REMOTE_ADDR']);
235
      $this->createSession($username, $getIPAddress, $lastLoginTime);
236
      if ($setIPAddress) {
237
        // send a notification if success_login is active
238
        $uid = $this->getUserId($username);
239
        $notifs = new Notification();
240
        $notifs->setDebug($this->debug);
241
        $notifs->setMysql($this->mysqli);
242
        $notifs->setSmarty($this->smarty);
243
        $notifs->setConfig($this->config);
244
        $notifs->setSetting($this->setting);
245
        $notifs->setErrorCodes($this->aErrorCodes);
246
        $ndata = $notifs->getNotificationSettings($uid);
247
        if ((array_key_exists('push_success_lo', $ndata) && $ndata['push_success_lo']) || (array_key_exists('success_login', $ndata) && $ndata['success_login'])){
248
          // seems to be active, let's send it
249
          $aDataN['username'] = $username;
250
          $aDataN['email'] = $this->getUserEmail($username);
251
          $aDataN['subject'] = 'Successful login notification';
252
          $aDataN['LOGINIP'] = $this->getCurrentIP();
253
          $aDataN['LOGINUSER'] = $username;
254
          $aDataN['LOGINTIME'] = date('m/d/y H:i:s');
255
          $notifs->sendNotification($uid, 'success_login', $aDataN);
256
        }
257
        return true;
258
      }
259
    }
260
    $this->setErrorMessage("Invalid username or password");
261
    $this->log->log('error', "Authentication failed for $username");
262 View Code Duplication
    if ($id = $this->getUserId($username)) {
263
      $this->incUserFailed($id);
264
      // Check if this account should be locked
265
      if (isset($this->config['maxfailed']['login']) && $this->getUserFailed($id) >= $this->config['maxfailed']['login']) {
266
        $this->setLocked($id, 1);
267
        $this->log->log("warn", "$username locked due to failed logins, saved is [".$this->getUserIp($this->getUserId($username))."]");
268
        if ($token = $this->token->createToken('account_unlock', $id)) {
269
          $aData['token'] = $token;
270
          $aData['username'] = $username;
271
          $aData['email'] = $this->getUserEmail($username);
272
          $aData['subject'] = 'Account auto-locked';
273
          $this->mail->sendMail('notifications/locked', $aData);
274
        }
275
      }
276
    }
277
278
    return false;
279
  }
280
281
  /**
282
   * Check the users PIN for confirmation
283
   * @param userID int User ID
284
   * @param pin int PIN to check
285
   * @return bool
286
   **/
287
  public function checkPin($userId, $pin='') {
288
    $this->debug->append("STA " . __METHOD__, 4);
289
    $this->debug->append("Confirming PIN for $userId and pin $pin", 2);
290
    $strPinHash = $this->getUserPinHashById($userId);
291
    $aPin = explode('$', $strPinHash);
292
    count($aPin) == 1 ? $pin_hash = $this->getHash($pin, 0) : $pin_hash = $this->getHash($pin, $aPin[1], $aPin[2]);
293
    $stmt = $this->mysqli->prepare("SELECT pin FROM $this->table WHERE id = ? AND pin = ? LIMIT 1");
294
    if ($stmt->bind_param('is', $userId, $pin_hash) && $stmt->execute() && $stmt->bind_result($row_pin) && $stmt->fetch()) {
295
      $this->setUserPinFailed($userId, 0);
296
      return ($pin_hash === $row_pin);
297
    }
298
    $this->log->log('info', $this->getUserName($userId).' incorrect pin');
299
    $this->incUserPinFailed($userId);
300
    // Check if this account should be locked
301 View Code Duplication
    if (isset($this->config['maxfailed']['pin']) && $this->getUserPinFailed($userId) >= $this->config['maxfailed']['pin']) {
302
      $this->setLocked($userId, 1);
303
      $this->log->log("warn", $this->getUserName($userId)." was locked due to incorrect pins");
304
      if ($token = $this->token->createToken('account_unlock', $userId)) {
305
        $username = $this->getUserName($userId);
306
        $aData['token'] = $token;
307
        $aData['username'] = $username;
308
        $aData['email'] = $this->getUserEmail($username);
309
        $aData['subject'] = 'Account auto-locked';
310
        $this->mail->sendMail('notifications/locked', $aData);
311
      }
312
      $this->logoutUser();
313
    }
314
    return false;
315
  }
316
317
  public function generatePin($userID, $current) {
318
    $this->debug->append("STA " . __METHOD__, 4);
319
    $username = $this->getUserName($userID);
320
    $email = $this->getUserEmail($username);
321
    $strPasswordHash = $this->getUserPasswordHashById($userID);
322
    $aPassword = explode('$', $strPasswordHash);
323
    count($aPassword) == 1 ? $password_hash = $this->getHash($current, 0) : $password_hash = $this->getHash($current, $aPassword[1], $aPassword[2]);
324
    $newpin = intval( '0' . rand(1,9) . rand(0,9) . rand(0,9) . rand(0,9) );
325
    $aData['username'] = $username;
326
    $aData['email'] = $email;
327
    $aData['pin'] = $newpin;
328
    $newpin = $this->getHash($newpin, HASH_VERSION, bin2hex(openssl_random_pseudo_bytes(32)));
329
    $aData['subject'] = 'PIN Reset Request';
330
    $stmt = $this->mysqli->prepare("UPDATE $this->table SET pin = ? WHERE ( id = ? AND pass = ? )");
331
    if ($this->checkStmt($stmt) && $stmt->bind_param('sis', $newpin, $userID, $password_hash) && $stmt->execute()) {
332
      if ($stmt->errno == 0 && $stmt->affected_rows === 1) {
333
        if ($this->mail->sendMail('pin/reset', $aData)) {
334
          $this->log->log("info", "$username was sent a pin reset e-mail");
335
          return true;
336
        } else {
337
          $this->log->log("warn", "$username request a pin reset but failed to send mail");
338
          $this->setErrorMessage('Unable to send mail to your address');
339
          return false;
340
        }
341
      }
342
    }
343
    $this->log->log("warn", "$username incorrect pin reset attempt");
344
    $this->setErrorMessage( 'Unable to generate PIN, current password incorrect?' );
345
    return false;
346
}
347
348
  /**
349
   * Get all users that have auto payout setup
350
   * @param none
351
   * @return data array All users with payout setup
352
   **/
353
  public function getAllAutoPayout() {
354
    $this->debug->append("STA " . __METHOD__, 4);
355
    $stmt = $this->mysqli->prepare("
356
      SELECT
357
        a.id, a.username, ca.coin_address AS coin_address, ca.ap_threshold
358
      FROM " . $this->getTableName() . " AS a
359
      LEFT JOIN " . $this->coin_address->getTableName() . " AS ca
360
      ON a.id = ca.account_id
361
      WHERE ca.ap_threshold > 0 AND ca.currency = ?
362
      AND ca.coin_address IS NOT NULL
363
      ");
364 View Code Duplication
    if ( $this->checkStmt($stmt) && $stmt->bind_param('s', $this->config['currency']) && $stmt->execute() && $result = $stmt->get_result()) {
365
      return $result->fetch_all(MYSQLI_ASSOC);
366
    }
367
    $this->debug->append("Unable to fetch users with AP set");
368
    return false;
369
  }
370
371
  /**
372
   * Fetch users donation value 
373
   * @param userID int UserID
374
   * @return data string Coin Address
375
   **/
376
  public function getDonatePercent($userID) {
377
    $this->debug->append("STA " . __METHOD__, 4);
378
    $dPercent = $this->getSingle($userID, 'donate_percent', 'id');
379
    if ($dPercent > 100) $dPercent = 100;
380
    if ($dPercent < 0) $dPercent = 0;
381
    return $dPercent;
382
  }
383
384
  /**
385
   * Send e-mail to confirm a change for 2fa
386
   * @param strType string Token type name
387
   * @param userID int User ID
388
   * @return bool
389
   */
390
  public function sendChangeConfigEmail($strType, $userID) {
391
    $exists = $this->token->doesTokenExist($strType, $userID);
392
    if ($exists == 0) {
393
      $token = $this->token->createToken($strType, $userID);
394
      $aData['token'] = $token;
395
      $aData['username'] = $this->getUserName($userID);
396
      $aData['email'] = $this->getUserEmail($aData['username']);
397
      switch ($strType) {
398
      	case 'account_edit':
399
      	  $aData['subject'] = 'Account detail change confirmation';
400
      	  break;
401
      	case 'change_pw':
402
      	  $aData['subject'] = 'Account password change confirmation';
403
      	  break;
404
      	case 'withdraw_funds':
405
      	  $aData['subject'] = 'Manual payout request confirmation';
406
      	  break;
407
      	default:
408
      	  $aData['subject'] = '';
409
      }
410
      $this->log->log("info", $aData['username']." was sent a $strType token e-mail");
411
      if ($this->mail->sendMail('notifications/'.$strType, $aData)) {
412
        return true;
413
      } else {
414
        $this->setErrorMessage('Failed to send the notification');
415
        $this->log->log("warn", $aData['username']." requested a $strType token but sending mail failed");
416
        return false;
417
      }
418
    }
419
    $this->log->log("warn", $this->getUserName($userID)." attempted to request multiple $strType tokens");
420
    $this->setErrorMessage('A request has already been sent to your e-mail address. Please wait an hour for it to expire.');
421
    return false;
422
  }
423
424
  /**
425
   * Update the accounts password
426
   * @param userID int User ID
427
   * @param current string Current password
428
   * @param new1 string New password
429
   * @param new2 string New password confirmation
430
   * @param strToken string Token for confirmation
431
   * @return bool
432
   **/
433
  public function updatePassword($userID, $current, $new1, $new2, $strToken) {
434
    $this->debug->append("STA " . __METHOD__, 4);
435
    if ($new1 !== $new2) {
436
      $this->setErrorMessage( 'New passwords do not match' );
437
      return false;
438
    }
439
    if ( strlen($new1) < 8 ) {
440
      $this->setErrorMessage( 'New password is too short, please use more than 8 chars' );
441
      return false;
442
    }
443
    $strPasswordHash = $this->getUserPasswordHashById($userID);
444
    $aPassword = explode('$', $strPasswordHash);
445
    count($aPassword) == 1 ? $password_hash = $this->getHash($current, 0) : $password_hash = $this->getHash($current, $aPassword[1], $aPassword[2]);
446
    $new = $this->getHash($new1, HASH_VERSION, bin2hex(openssl_random_pseudo_bytes(32)));
447 View Code Duplication
    if ($this->config['twofactor']['enabled'] && $this->config['twofactor']['options']['changepw']) {
448
      $tValid = $this->token->isTokenValid($userID, $strToken, 6);
449
      if ($tValid) {
450
        if ($this->token->deleteToken($strToken)) {
451
          $this->log->log("info", $this->getUserName($userID)." deleted change password token");
452
          // token deleted, continue
453
        } else {
454
          $this->log->log("warn", $this->getUserName($userID)." failed to delete the change password token");
455
          $this->setErrorMessage('Token deletion failed');
456
          return false;
457
        }
458
      } else {
459
        $this->log->log("error", $this->getUserName($userID)." attempted to use an invalid change password token");
460
        $this->setErrorMessage('Invalid token');
461
        return false;
462
      }
463
    }
464
    $stmt = $this->mysqli->prepare("UPDATE $this->table SET pass = ? WHERE ( id = ? AND pass = ? )");
465
    if ($this->checkStmt($stmt)) {
466
      $stmt->bind_param('sis', $new, $userID, $password_hash);
467
      $stmt->execute();
468
      if ($stmt->errno == 0 && $stmt->affected_rows === 1) {
469
        $this->log->log("info", $this->getUserName($userID)." updated password");
470
        return true;
471
      }
472
      $stmt->close();
473
    }
474
    $this->log->log("warn", $this->getUserName($userID)." incorrect password update attempt");
475
    $this->setErrorMessage( 'Unable to update password, current password wrong?' );
476
    return false;
477
  }
478
479
  /**
480
   * Update account information from the edit account page
481
   * @param userID int User ID
482
   * @param address string new coin address
483
   * @param threshold float auto payout threshold
484
   * @param donat float donation % of income
485
   * @param strToken string Token for confirmation
486
   * @return bool
487
   **/
488
  public function updateAccount($userID, $address, $threshold, $donate, $email, $timezone, $is_anonymous, $strToken) {
489
    $this->debug->append("STA " . __METHOD__, 4);
490
    $bUser = false;
491
    $donate = round($donate, 2);
492
    // number validation checks
493
    if (!is_numeric($threshold)) {
494
      $this->setErrorMessage('Invalid input for auto-payout');
495
      return false;
496
    } else if ($threshold < $this->config['ap_threshold']['min'] && $threshold != 0) {
497
      $this->setErrorMessage('Threshold below configured minimum of ' . $this->config['ap_threshold']['min']);
498
      return false;
499
    } else if ($threshold > $this->config['ap_threshold']['max']) {
500
      $this->setErrorMessage('Threshold above configured maximum of ' . $this->config['ap_threshold']['max']);
501
      return false;
502
    }
503
    if (!is_numeric($donate)) {
504
      $this->setErrorMessage('Invalid input for donation');
505
      return false;
506
    } else if ($donate < $this->config['donate_threshold']['min'] && $donate != 0) {
507
      $this->setErrorMessage('Donation below allowed ' . $this->config['donate_threshold']['min'] . '% limit');
508
      return false;
509
    } else if ($donate > 100) {
510
      $this->setErrorMessage('Donation above allowed 100% limit');
511
      return false;
512
    }
513
    if ($email != 'hidden' && $email != NULL && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
514
      $this->setErrorMessage('Invalid email address');
515
      return false;
516
    }
517
    if (!empty($address)) {
518 View Code Duplication
      if ($address != $this->coin_address->getCoinAddress($userID) && $this->coin_address->existsCoinAddress($address)) {
519
        $this->setErrorMessage('Address is already in use');
520
        return false;
521
      }
522
      if ($this->bitcoin->can_connect() === true) {
523
        if (!$this->bitcoin->validateaddress($address)) {
524
          $this->setErrorMessage('Invalid coin address');
525
          return false;
526
        }
527
      } else {
528
        $this->setErrorMessage('Unable to connect to RPC server for coin address validation');
529
        return false;
530
      }
531
    } else {
532
      $address = NULL;
533
    }
534
535
    // Number sanitizer, just in case we fall through above
536
    $threshold = min($this->config['ap_threshold']['max'], max(0, floatval($threshold)));
537
    $donate = min(100, max(0, floatval($donate)));
538
539
    // twofactor - consume the token if it is enabled and valid
540 View Code Duplication
    if ($this->config['twofactor']['enabled'] && $this->config['twofactor']['options']['details']) {
541
      $tValid = $this->token->isTokenValid($userID, $strToken, 5);
542
      if ($tValid) {
543
        if ($this->token->deleteToken($strToken)) {
544
          $this->log->log("info", $this->getUserName($userID)." deleted account update token");
545
        } else {
546
          $this->setErrorMessage('Token deletion failed');
547
          $this->log->log("warn", $this->getUserName($userID)." updated their account details but failed to delete token");
548
          return false;
549
        }
550
      } else {
551
        $this->setErrorMessage('Invalid token');
552
        $this->log->log("warn", $this->getUserName($userID)." attempted to use an invalid token account update token");
553
        return false;
554
      }
555
    }
556
557
    // If we hide our email or it's not set, fetch current one to update
558
    if ($email == 'hidden' || $email == NULL)
559
      $email = $this->getUserEmailById($userID);
560
    // We passed all validation checks so update the account
561
    $stmt = $this->mysqli->prepare("UPDATE $this->table SET donate_percent = ?, email = ?, timezone = ?, is_anonymous = ? WHERE id = ?");
562
    if ($this->checkStmt($stmt) && $stmt->bind_param('dssii', $donate, $email, $timezone, $is_anonymous, $userID) && $stmt->execute()) {
563
      $this->log->log("info", $this->getUserName($userID)." updated their account details");
564
      // Update coin address and ap_threshold if coin_address is set
565
      if ($address) {
566
        if ($this->coin_address->update($userID, $address, $threshold)) {
567
          return true;
568
        }
569
      } else {
570
        if ($this->coin_address->remove($userID, $address)) {
571
          return true;
572
        }
573
      }
574
    }
575
    // Catchall
576
    $this->setErrorMessage('Failed to update your account');
577
    $this->debug->append('Account update failed: ' . $this->mysqli->error);
578
    return false;
579
  }
580
581
  /**
582
   * Check API key for authentication
583
   * @param key string API key hash
584
   * @return bool
585
   **/
586
  public function checkApiKey($key) {
587
    $this->debug->append("STA " . __METHOD__, 4);
588
    if (!is_string($key)) return false;
589
    $stmt = $this->mysqli->prepare("SELECT api_key, id FROM $this->table WHERE api_key = ? LIMIT 1");
590
    if ($this->checkStmt($stmt) && $stmt->bind_param("s", $key) && $stmt->execute() && $stmt->bind_result($api_key, $id) && $stmt->fetch()) {
591
      if ($api_key === $key)
592
        return $id;
593
    }
594
    header("HTTP/1.1 401 Unauthorized");
595
    die('Access denied');
596
  }
597
598
  /**
599
   * Check a password for a user
600
   * @param username string Username
601
   * @param password string Password
602
   * @return bool
603
   **/
604
  private function checkUserPassword($username, $password) {
605
    $this->debug->append("STA " . __METHOD__, 4);
606
    $user = array();
607
    $stmt = $this->mysqli->prepare("SELECT username, pass, id, timezone, is_admin FROM $this->table WHERE LOWER(username) = LOWER(?) LIMIT 1");
608
    if ($this->checkStmt($stmt) && $stmt->bind_param('s', $username) && $stmt->execute() && $stmt->bind_result($row_username, $row_password, $row_id, $row_timezone, $row_admin)) {
609
      $stmt->fetch();
610
      $stmt->close();
611
      $aPassword = explode('$', $row_password);
612
      count($aPassword) == 1 ? $password_hash = $this->getHash($password, 0) : $password_hash = $this->getHash($password, $aPassword[1], $aPassword[2]);
613
      // Store the basic login information
614
      $this->user = array('username' => $row_username, 'id' => $row_id, 'timezone' => $row_timezone, 'is_admin' => $row_admin);
615
      return $password_hash === $row_password && strtolower($username) === strtolower($row_username);
616
    }
617
    return $this->sqlError();
618
  }
619
620
  /**
621
   * Create a PHP session for a user
622
   * @param username string Username to create session for
623
   * @return none
624
   **/
625
  private function createSession($username, $lastIP='', $lastLoginTime='') {
0 ignored issues
show
The parameter $username is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
createSession uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
createSession uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
626
    $this->debug->append("STA " . __METHOD__, 4);
627
    $this->debug->append("Log in user to _SESSION", 2);
628
    if (!empty($lastIP) && (!empty($lastLoginTime))) {
629
      $_SESSION['last_ip_pop'] = array($lastIP, $lastLoginTime);
630
    }
631
    session_regenerate_id(true);
632
    $_SESSION['AUTHENTICATED'] = '1';
633
    // $this->user from checkUserPassword
634
    $_SESSION['USERDATA'] = $this->user;
635
    if ($this->config['protect_session_state']) {
636
      $_SESSION['STATE'] = md5($_SESSION['USERDATA']['username'].$_SESSION['USERDATA']['id'].@$_SERVER['HTTP_USER_AGENT']);
637
    }
638
  }
639
640
  /**
641
   * Update users last_login timestamp
642
   * @param id int UserID
643
   * @return bool true of false
644
   **/
645
  private function updateLoginTimestamp($id) {
646
    $field = array('name' => 'last_login', 'type' => 'i', 'value' => time());
647
    return $this->updateSingle($id, $field);
648
  }
649
650
  /**
651
   * Log out current user, destroy the session
652
   * @param none
653
   * @return true
654
   **/
655
  public function logoutUser() {
0 ignored issues
show
logoutUser uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
logoutUser uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
656
    $this->debug->append("STA " . __METHOD__, 4);
657
    // Unset all of the session variables
658
    $_SESSION = array();
659
    // As we're killing the sesison, also kill the cookie!
660
    setcookie(session_name(), '', time() - 42000);
661
    // Destroy the session.
662
    session_destroy();
663
    // Enforce generation of a new Session ID and delete the old
664
    session_regenerate_id(true);
665
666
    // Enforce a page reload and point towards login with referrer included, if supplied
667
    $port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ? "" : (":".$_SERVER["SERVER_PORT"]);
668
    $pushto = $_SERVER['SCRIPT_NAME'].'?page=login';
669
    $location = (@$_SERVER['HTTPS'] == 'on') ? 'https://' . $_SERVER['SERVER_NAME'] . $port . $pushto : 'http://' . $_SERVER['SERVER_NAME'] . $port . $pushto;
670
    if (!headers_sent()) header('Location: ' . $location);
671
    exit('<meta http-equiv="refresh" content="0; url=' . $location . '"/>');
672
  }
673
674
  /**
675
   * Get all users for admin panel
676
   **/
677
  public function getAllUsers($filter='%') {
678
    $this->debug->append("STA " . __METHOD__, 4);
679
    $stmt = $this->mysqli->prepare("
680
      SELECT
681
      a.id AS id,
682
      a.username AS username
683
      FROM " . $this->getTableName() . " AS a
684
      WHERE a.username LIKE ?
685
      GROUP BY username");
686 View Code Duplication
    if ($this->checkStmt($stmt) && $stmt->bind_param('s', $filter) && $stmt->execute() && $result = $stmt->get_result()) {
687
      while ($row = $result->fetch_assoc()) {
688
        $aData[$row['id']] = $row['username'];
689
      }
690
      return $aData;
691
    }
692
    return false;
693
  }
694
695
  /**
696
   * Fetch this classes table name
697
   * @return table string This classes table name
698
   **/
699
  public function getTableName() {
700
    $this->debug->append("STA " . __METHOD__, 4);
701
    return $this->table;
702
  }
703
704
  /**
705
   * Fetch some basic user information to store for later user
706
   * @param userID int User ID
707
   * return data array Database fields as used in SELECT
708
   **/
709
  public function getUserData($userID) {
710
    $this->debug->append("STA " . __METHOD__, 4);
711
    $this->debug->append("Fetching user information for user id: $userID");
712
    $stmt = $this->mysqli->prepare("
713
      SELECT
714
      id AS id, username, pin, api_key, is_admin, is_anonymous, email, timezone, no_fees,
715
      IFNULL(donate_percent, '0') as donate_percent
716
      FROM " . $this->getTableName() . "
717
      WHERE id = ? LIMIT 0,1");
718
    if ($this->checkStmt($stmt) && $stmt->bind_param('i', $userID) && $stmt->execute() && $result = $stmt->get_result()) {
719
      $aData = $result->fetch_assoc();
720
      $aData['coin_address'] = $this->coin_address->getCoinAddress($userID);
721
      if (! $aData['ap_threshold'] = $this->coin_address->getAPThreshold($userID))
722
        $aData['ap_threshold'] = 0;
723
      $stmt->close();
724
      return $aData;
725
    }
726
    $this->debug->append("Failed to fetch user information for $userID");
727
    return $this->sqlError();
728
  }
729
730
  /**
731
   * Register a new user in the system
732
   * @param username string Username
733
   * @param password1 string Password
734
   * @param password2 string Password verification
735
   * @param pin int 4 digit PIN code
736
   * @param email1 string Email address
737
   * @param email2 string Email confirmation
738
   * @return bool
739
   **/
740
  public function register($username, $coinaddress, $password1, $password2, $pin, $email1='', $email2='', $tac='', $strToken='') {
741
    $this->debug->append("STA " . __METHOD__, 4);
742
    if ($tac != 1) {
743
      $this->setErrorMessage('You need to accept our <a href="'.$_SERVER['SCRIPT_NAME'].'?page=tac" target="_blank">Terms and Conditions</a>');
744
      return false;
745
    }
746
    if (strlen($username) > 40) {
747
      $this->setErrorMessage('Username exceeding character limit');
748
      return false;
749
    }
750
    if (!is_null($coinaddress)) {
751
      if ($this->coin_address->existsCoinAddress($coinaddress)) {
752
        $this->setErrorMessage('Coin address is already taken');
753
        return false;
754
      }
755
      if (!$this->bitcoin->validateaddress($coinaddress)) {
756
        $this->setErrorMessage('Coin address is not valid');
757
        return false;
758
      }
759
    }
760
    if (preg_match('/[^a-z_\-0-9]/i', $username)) {
761
      $this->setErrorMessage('Username may only contain alphanumeric characters');
762
      return false;
763
    }
764
    if ($this->getEmail($email1)) {
765
      $this->setErrorMessage( 'This e-mail address is already taken' );
766
      return false;
767
    }
768
    if (strlen($password1) < 8) {
769
      $this->setErrorMessage( 'Password is too short, minimum of 8 characters required' );
770
      return false;
771
    }
772
    if ($password1 !== $password2) {
773
      $this->setErrorMessage( 'Password do not match' );
774
      return false;
775
    }
776 View Code Duplication
    if (empty($email1) || !filter_var($email1, FILTER_VALIDATE_EMAIL)) {
777
      $this->setErrorMessage( 'Invalid e-mail address' );
778
      return false;
779
    }
780
    if ($email1 !== $email2) {
781
      $this->setErrorMessage( 'E-mail do not match' );
782
      return false;
783
    }
784
    if (!is_numeric($pin) || strlen($pin) > 4 || strlen($pin) < 4) {
785
      $this->setErrorMessage( 'Invalid PIN' );
786
      return false;
787
    }
788
    if (isset($strToken) && !empty($strToken)) {
789
      if ( ! $aToken = $this->token->getToken($strToken, 'invitation')) {
790
        $this->setErrorMessage('Unable to find token');
791
        return false;
792
      }
793
      // Circle dependency, so we create our own object here
794
      $invitation = new Invitation();
795
      $invitation->setMysql($this->mysqli);
796
      $invitation->setDebug($this->debug);
797
      $invitation->setLog($this->log);
798
      $invitation->setUser($this);
799
      $invitation->setConfig($this->config);
800
      if (!$invitation->setActivated($aToken['id'])) {
801
        $this->setErrorMessage('Unable to activate your invitation');
802
        return false;
803
      }
804
      if (!$this->token->deleteToken($strToken)) {
805
        $this->setErrorMessage('Unable to remove used token');
806
        $this->log->log("warn", "$username tried to register but failed to delete the invitation token");
807
        return false;
808
      }
809
    }
810
    if ($this->mysqli->query("SELECT id FROM $this->table LIMIT 1")->num_rows > 0) {
811
      ! $this->setting->getValue('accounts_confirm_email_disabled') ? $is_locked = 1 : $is_locked = 0;
812
      $is_admin = 0;
813
      $stmt = $this->mysqli->prepare("
814
        INSERT INTO $this->table (username, pass, email, signup_timestamp, pin, api_key, is_locked)
815
        VALUES (?, ?, ?, ?, ?, ?, ?)
816
        ");
817
    } else {
818
      $is_locked = 0;
819
      $is_admin = 1;
820
      $stmt = $this->mysqli->prepare("
821
        INSERT INTO $this->table (username, pass, email, signup_timestamp, pin, api_key, is_admin, is_locked)
822
        VALUES (?, ?, ?, ?, ?, ?, 1, ?)
823
        ");
824
    }
825
826
    // Create hashed strings using original string and salt
827
    $password_hash = $this->getHash($password1, HASH_VERSION, bin2hex(openssl_random_pseudo_bytes(32)));
828
    $pin_hash = $this->getHash($pin, HASH_VERSION, bin2hex(openssl_random_pseudo_bytes(32)));
829
    $apikey_hash = $this->getHash($username, 0);
830
    $username_clean = strip_tags($username);
831
    $signup_time = time();
832
833
    if ($this->checkStmt($stmt) && $stmt->bind_param('sssissi', $username_clean, $password_hash, $email1, $signup_time, $pin_hash, $apikey_hash, $is_locked) && $stmt->execute()) {
834
      $new_account_id = $this->mysqli->insert_id;
835
      if (!is_null($coinaddress)) $this->coin_address->add($new_account_id, $coinaddress);
836
      if (! $this->setting->getValue('accounts_confirm_email_disabled') && $is_admin != 1) {
837
        if ($token = $this->token->createToken('confirm_email', $stmt->insert_id)) {
838
          $aData['username'] = $username_clean;
839
          $aData['token'] = $token;
840
          $aData['email'] = $email1;
841
          $aData['subject'] = 'E-Mail verification';
842 View Code Duplication
          if (!$this->mail->sendMail('register/confirm_email', $aData)) {
843
            $this->setErrorMessage('Unable to request email confirmation: ' . $this->mail->getError());
844
            return false;
845
          }
846
          return true;
847
        } else {
848
          $this->setErrorMessage('Failed to create confirmation token');
849
          $this->debug->append('Unable to create confirm_email token: ' . $this->token->getError());
850
          return false;
851
        }
852
      } else {
853
        return true;
854
      }
855
    } else {
856
      $this->setErrorMessage( 'Unable to register' );
857
      $this->debug->append('Failed to insert user into DB: ' . $this->mysqli->error);
858
      echo $this->mysqli->error;
859
      if ($stmt->sqlstate == '23000') $this->setErrorMessage( 'Username or email already registered' );
860
      return false;
861
    }
862
    return false;
863
  }
864
865
  /**
866
   * User a one time token to reset a password
867
   * @param token string one time token
868
   * @param new1 string New password
869
   * @param new2 string New password verification
870
   * @return bool
871
   **/
872
  public function resetPassword($token, $new1, $new2) {
873
    $this->debug->append("STA " . __METHOD__, 4);
874
    if ($aToken = $this->token->getToken($token, 'password_reset')) {
875
      if ($new1 !== $new2) {
876
        $this->setErrorMessage( 'New passwords do not match' );
877
        return false;
878
      }
879
      if ( strlen($new1) < 8 ) { 
880
        $this->setErrorMessage( 'New password is too short, please use more than 8 chars' );
881
        return false;
882
      }
883
      $new_hash = $this->getHash($new1, HASH_VERSION, bin2hex(openssl_random_pseudo_bytes(32)));
884
      $stmt = $this->mysqli->prepare("UPDATE $this->table SET pass = ? WHERE id = ?");
885
      if ($this->checkStmt($stmt) && $stmt->bind_param('si', $new_hash, $aToken['account_id']) && $stmt->execute() && $stmt->affected_rows === 1) {
886
        if ($this->token->deleteToken($aToken['token'])) {
887
          return true;
888
        } else {
889
          $this->setErrorMessage('Unable to invalidate used token');
890
        }
891
      } else {
892
        $this->setErrorMessage('Unable to set new password or you chose the same password. Please use a different one.');
893
      }
894
    } else {
895
      $this->setErrorMessage('Invalid token: ' . $this->token->getError());
896
    }
897
    $this->debug->append('Failed to update password:' . $this->mysqli->error);
898
    return false;
899
  }
900
901
  /**
902
   * Reset a password by sending a password reset mail
903
   * @param username string Username to reset password for
904
   * @return bool
905
   **/
906
  public function initResetPassword($username) {
0 ignored issues
show
initResetPassword uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
907
    $this->debug->append("STA " . __METHOD__, 4);
908
    // Fetch the users mail address
909
    if (empty($username)) {
910
      $this->setErrorMessage("Username must not be empty");
911
      return false;
912
    }
913
    if (filter_var($username, FILTER_VALIDATE_EMAIL)) {
914
      $this->debug->append("Username is an e-mail: $username", 2);
915
      if (!$username = $this->getUserNameByEmail($username)) {
916
        $this->setErrorMessage("Invalid username or password.");
917
        return false;
918
      }
919
    }
920
    if (!$aData['email'] = $this->getUserEmail($username, true)) {
921
      $this->setErrorMessage("Please check your mail account to finish your password reset");
922
      return false;
923
    }
924 View Code Duplication
    if (!$aData['token'] = $this->token->createToken('password_reset', $this->getUserId($username, true))) {
925
      $this->setErrorMessage('Unable to setup token for password reset');
926
      return false;
927
    }
928
    $aData['username'] = $this->getUserName($this->getUserId($username, true));
929
    $aData['subject'] = 'Password Reset Request';
930
    if ($_SERVER['REMOTE_ADDR'] !== $this->getUserIp($this->getUserId($username, true))) {
931
      $this->log->log("warn", "$username requested password reset, saved IP is [".$this->getUserIp($this->getUserId($username, true))."]");
932
    } else {
933
      $this->log->log("info", "$username requested password reset, saved IP is [".$this->getUserIp($this->getUserId($username, true))."]");
934
    }
935 View Code Duplication
    if ($this->mail->sendMail('password/reset', $aData)) {
936
        return true;
937
      } else {
938
        $this->setErrorMessage('Unable to send mail to your address');
939
        return false;
940
      }
941
    return false;
942
  }
943
944
  /**
945
   * Check if a user is authenticated and allowed to login
946
   * Checks the $_SESSION for existing data
947
   * Destroys the session if account is now locked
948
   * @param none
949
   * @return bool
950
   **/
951
public function isAuthenticated($logout=true) {
0 ignored issues
show
isAuthenticated uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
isAuthenticated uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
952
    $this->debug->append("STA " . __METHOD__, 4);
953
    if ( @$_SESSION['AUTHENTICATED'] == true &&
954
         !$this->isLocked($_SESSION['USERDATA']['id']) &&
955
         $this->getUserIp($_SESSION['USERDATA']['id']) == $_SERVER['REMOTE_ADDR'] &&
956
         ( ! $this->config['protect_session_state'] ||
957
           (
958
             $this->config['protect_session_state'] && $_SESSION['STATE'] == md5($_SESSION['USERDATA']['username'].$_SESSION['USERDATA']['id'].@$_SERVER['HTTP_USER_AGENT'])
959
           )
960
         )
961
    ) return true;
962
    // Catchall
963
    $this->log->log('warn', 'Forcing logout, user is locked or IP changed mid session [hijack attempt?]');
964
    if ($logout == true) $this->logoutUser();
965
    return false;
966
  }
967
968
  /**
969
   * Convenience function to get IP address, no params is the same as REMOTE_ADDR
970
   * @param trustremote bool must be FALSE to checkcloudflare, checkclient or checkforwarded
971
   * @param checkcloudflare bool check HTTP_CF_CONNECTING_IP for a valid ip first
972
   * @param checkclient bool check HTTP_CLIENT_IP for a valid ip first
973
   * @param checkforwarded bool check HTTP_X_FORWARDED_FOR for a valid ip first
974
   * @return string IP address
975
   */
976
  public function getCurrentIP($trustremote=false, $checkcloudflare=true, $checkclient=false, $checkforwarded=true) {
977
    $cf = (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) ? $_SERVER['HTTP_CF_CONNECTING_IP'] : false;
978
    $client = (isset($_SERVER['HTTP_CLIENT_IP'])) ? $_SERVER['HTTP_CLIENT_IP'] : false;
979
    $fwd = (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : false;
980
    $remote = (isset($_SERVER['REMOTE_ADDR'])) ? $_SERVER['REMOTE_ADDR'] : @$_SERVER['REMOTE_ADDR'];
981
    // shared internet
982
    if (!$trustremote && $checkcloudflare && filter_var($cf, FILTER_VALIDATE_IP)) {
983
      // cloudflare
984
      return $cf;
985
    } else if (!$trustremote && $checkclient && filter_var($client, FILTER_VALIDATE_IP)) {
986
      return $client;
987
    } else if (!$trustremote && $checkforwarded && strpos($fwd, ',') !== false) {
988
      // multiple proxies
989
      $ips = explode(',', $fwd);
990
      return $ips[0];
991
    } else if (!$trustremote && $checkforwarded && filter_var($fwd, FILTER_VALIDATE_IP)) {
992
      // single
993
      return $fwd;
994
    } else {
995
      // as usual
996
      return $remote;
997
    }
998
  }
999
}
1000
1001
// Make our class available automatically
1002
$user = new User($config);
1003
$user->setDebug($debug);
1004
$user->setLog($log);
1005
$user->setMysql($mysqli);
1006
$user->setSalt($config['SALT']);
1007
$user->setSmarty($smarty);
1008
$user->setMail($mail);
1009
$user->setToken($oToken);
1010
$user->setBitcoin($bitcoin);
1011
$user->setSetting($setting);
1012
$user->setCoinAddress($coin_address);
1013
$user->setErrorCodes($aErrorCodes);
1014