Statistics   F
last analyzed

Complexity

Total Complexity 201

Size/Duplication

Total Lines 908
Duplicated Lines 7.49 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 201
lcom 1
cbo 1
dl 68
loc 908
ccs 0
cts 702
cp 0
rs 1.692
c 0
b 0
f 0

33 Methods

Rating   Name   Duplication   Size   Complexity  
A setGetCache() 0 3 1
A getGetCache() 0 3 1
A getAllUserMiningStats() 0 3 1
A getUserStatsTableName() 0 3 1
A getFirstBlockFound() 0 9 5
B getLastBlocksbyTime() 0 54 5
A getBlocksFound() 17 17 6
A getBlocksFoundHeight() 3 18 6
B getBlocksSolvedbyAccount() 0 20 6
A getBlocksSolvedbyWorker() 3 16 6
A updateShareStatistics() 0 6 4
A insertPPLNSStatistics() 0 6 4
B getCurrentHashrate() 0 25 7
B getCurrentShareRate() 22 22 6
B getRoundShares() 0 26 7
B getAllUserShares() 0 41 8
B getUserShares() 0 22 8
C getAllUserStats() 0 65 17
B fetchAllUserMiningStats() 0 43 6
A storeAllUserMiningStatsSnapshot() 0 19 6
B getUserUnpaidPPSShares() 0 15 7
B getUserMiningStats() 0 43 10
D getTopContributors() 6 81 24
B getHourlyMiningStatsByAccount() 0 21 7
B getUserEstimates() 0 37 8
A getPoolStatsHours() 0 19 6
A getEstimatedShares() 0 3 1
A getExpectedTimePerBlock() 0 18 5
A getExpectedNextDifficulty() 0 13 3
A getBlocksUntilDiffChange() 0 11 3
B getPPSValue() 0 23 6
A getCountAllActiveUsers() 12 12 6
A purgeUserStats() 1 7 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Statistics often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Statistics, and based on these observations, apply Extract Interface, too.

1
<?php
2
$defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1;
3
4
5
/*
6
 * We give access to plenty of statistics through this class
7
 * Statistics should be non-intrusive and not change any
8
 * rows in our database to ensure data integrity for the backend
9
 **/
10
class Statistics extends Base {
11
  protected $table = 'statistics_shares';
12
  protected $table_user_stats = 'statistics_users';
13
  private $getcache = true;
14
15
  // Disable fetching values from cache
16
  public function setGetCache($set=false) {
17
    $this->getcache = $set;
18
  }
19
  public function getGetCache() {
20
    return $this->getcache;
21
  }
22
  public function getAllUserMiningStats() {
23
    return $this->allUserMiningStats;
0 ignored issues
show
Bug introduced by
The property allUserMiningStats 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...
24
  }
25
  public function getUserStatsTableName() {
26
    return $this->table_user_stats;
27
  }
28
29
  /**
30
   * Get our first block found
31
   *
32
   **/
33
  public function getFirstBlockFound() {
34
    $this->debug->append("STA " . __METHOD__, 4);
35
    if ($data = $this->memcache->get(__FUNCTION__)) return $data;
0 ignored issues
show
Bug introduced by
The property memcache 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...
36
    $stmt = $this->mysqli->prepare("
37
      SELECT IFNULL(MIN(time), 0) AS time FROM " . $this->block->getTableName());
0 ignored issues
show
Bug introduced by
The property block 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...
38
    if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result())
39
      return $result->fetch_object()->time;
40
    return false;
41
  }
42
43
  /**
44
   * Fetch last found blocks by time
45
   **/
46
  function getLastBlocksbyTime() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
47
    $this->debug->append("STA " . __METHOD__, 4);
48
    if ($data = $this->memcache->get(__FUNCTION__)) return $data;
49
    $stmt = $this->mysqli->prepare("
50
      SELECT
51
        COUNT(id) AS Total,
52
        IFNULL(SUM(IF(confirmations > 0, 1, 0)), 0) AS TotalValid,
53
        IFNULL(SUM(IF(confirmations = -1, 1, 0)), 0) AS TotalOrphan,
54
        IFNULL(SUM(IF(confirmations > 0, difficulty, 0)), 0) AS TotalDifficulty,
55
        IFNULL(SUM(IF(confirmations > -1, shares, 0)), 0) AS TotalShares,
56
        IFNULL(SUM(IF(confirmations > -1, amount, 0)), 0) AS TotalAmount,
57
        IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), 1, 0)), 0) AS 1HourTotal,
58
        IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), 1, 0)), 0) AS 1HourValid,
59
        IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), 1, 0)), 0) AS 1HourOrphan,
60
        IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), difficulty, 0)), 0) AS 1HourDifficulty,
61
        IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), shares, 0)), 0) AS 1HourShares,
62
        IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), amount, 0)), 0) AS 1HourAmount,
63
        IFNULL(SUM(IF(FROM_UNIXTIME(time)    >= DATE_SUB(now(), INTERVAL 86400 SECOND), 1, 0)), 0) AS 24HourTotal,
64
        IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), 1, 0)), 0) AS 24HourValid,
65
        IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), 1, 0)), 0) AS 24HourOrphan,
66
        IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), difficulty, 0)), 0) AS 24HourDifficulty,
67
        IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), shares, 0)), 0) AS 24HourShares,
68
        IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), amount, 0)), 0) AS 24HourAmount,
69
        IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), 1, 0)), 0) AS 7DaysTotal,
70
        IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), 1, 0)), 0) AS 7DaysValid,
71
        IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), 1, 0)), 0) AS 7DaysOrphan,
72
        IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), difficulty, 0)), 0) AS 7DaysDifficulty,
73
        IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), shares, 0)), 0) AS 7DaysShares,
74
        IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), amount, 0)), 0) AS 7DaysAmount,
75
        IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), 1, 0)), 0) AS 4WeeksTotal,
76
        IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), 1, 0)), 0) AS 4WeeksValid,
77
        IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), 1, 0)), 0) AS 4WeeksOrphan,
78
        IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), difficulty, 0)), 0) AS 4WeeksDifficulty,
79
        IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), shares, 0)), 0) AS 4WeeksShares,
80
        IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), amount, 0)), 0) AS 4WeeksAmount,
81
        IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), 1, 0)), 0) AS 12MonthTotal,
82
        IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), 1, 0)), 0) AS 12MonthValid,
83
        IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), 1, 0)), 0) AS 12MonthOrphan,
84
        IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), difficulty, 0)), 0) AS 12MonthDifficulty,
85
        IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), shares, 0)), 0) AS 12MonthShares,
86
        IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), amount, 0)), 0) AS 12MonthAmount
87
      FROM " . $this->block->getTableName());
88
    if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) {
89
      $aData = $result->fetch_assoc();
90
      $aData['TotalEstimatedShares'] = $this->coin->calcEstaimtedShares($aData['TotalDifficulty']);
0 ignored issues
show
Bug introduced by
The property coin 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...
91
      $aData['1HourEstimatedShares'] = $this->coin->calcEstaimtedShares($aData['1HourDifficulty']);
92
      $aData['24HourEstimatedShares'] = $this->coin->calcEstaimtedShares($aData['24HourDifficulty']);
93
      $aData['7DaysEstimatedShares'] = $this->coin->calcEstaimtedShares($aData['7DaysDifficulty']);
94
      $aData['4WeeksEstimatedShares'] = $this->coin->calcEstaimtedShares($aData['4WeeksDifficulty']);
95
      $aData['12MonthEstimatedShares'] = $this->coin->calcEstaimtedShares($aData['12MonthDifficulty']);
96
    	return $this->memcache->setCache(__FUNCTION__, $aData);
97
    }
98
    return $this->sqlError();
99
  }
100
101
  /**
102
   * Get our last $limit blocks found
103
   * @param limit int Last limit blocks
104
   * @return array
105
   **/
106 View Code Duplication
  public function getBlocksFound($limit=10) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
107
    $this->debug->append("STA " . __METHOD__, 4);
108
    if ($data = $this->memcache->get(__FUNCTION__ . $limit)) return $data;
109
    $stmt = $this->mysqli->prepare("
110
      SELECT
111
        b.*,
112
        a.username AS finder,
113
        a.is_anonymous AS is_anonymous,
114
        ROUND(difficulty * POW(2, 32 - " . $this->coin->getTargetBits() . "), " . $this->coin->getShareDifficultyPrecision() . ") AS estshares
115
      FROM " . $this->block->getTableName() . " AS b
116
      LEFT JOIN " . $this->user->getTableName() . " AS a
0 ignored issues
show
Bug introduced by
The property user 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...
117
      ON b.account_id = a.id
118
      ORDER BY height DESC LIMIT ?");
119
    if ($this->checkStmt($stmt) && $stmt->bind_param("i", $limit) && $stmt->execute() && $result = $stmt->get_result())
120
      return $this->memcache->setCache(__FUNCTION__ . $limit, $result->fetch_all(MYSQLI_ASSOC), 5);
121
    return $this->sqlError();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sqlError(); (boolean) is incompatible with the return type documented by Statistics::getBlocksFound of type array.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
122
  }
123
124
  /**
125
   * Get our last $limit blocks found by height
126
   * @param limit int Last limit blocks
127
   * @return array
128
   **/
129
  public function getBlocksFoundHeight($iHeight=0, $limit=10) {
130
    $this->debug->append("STA " . __METHOD__, 4);
131
    if ($data = $this->memcache->get(__FUNCTION__ . $iHeight . $limit)) return $data;
132
    $stmt = $this->mysqli->prepare("
133
      SELECT
134
        b.*,
135
        a.username AS finder,
136
        a.is_anonymous AS is_anonymous,
137
        ROUND(difficulty * POW(2, 32 - " . $this->coin->getTargetBits() . "), 4) AS estshares
138
      FROM " . $this->block->getTableName() . " AS b
139
      LEFT JOIN " . $this->user->getTableName() . " AS a 
140
      ON b.account_id = a.id
141
      WHERE b.height <= ?
142
      ORDER BY height DESC LIMIT ?");
143 View Code Duplication
    if ($this->checkStmt($stmt) && $stmt->bind_param("ii", $iHeight, $limit) && $stmt->execute() && $result = $stmt->get_result())
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
144
      return $this->memcache->setCache(__FUNCTION__ . $iHeight . $limit, $result->fetch_all(MYSQLI_ASSOC), 5);
145
    return $this->sqlError();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sqlError(); (boolean) is incompatible with the return type documented by Statistics::getBlocksFoundHeight of type array.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
146
  }
147
148
  /**
149
   * Get SUM of blocks found and generated Coins for each Account
150
   * @param limit int Last limit blocks
151
   * @return array
152
   **/
153
  public function getBlocksSolvedbyAccount($limit=25) {
154
    $this->debug->append("STA " . __METHOD__, 4);
155
    if ($data = $this->memcache->get(__FUNCTION__ . $limit)) return $data;
156
    $stmt = $this->mysqli->prepare("
157
      SELECT
158
        b.*,
159
        a.username AS finder,
160
        a.is_anonymous AS is_anonymous,
161
        COUNT(b.id) AS solvedblocks, 
162
        SUM(b.amount) AS generatedcoins
163
      FROM " . $this->block->getTableName() . " AS b
164
      LEFT JOIN " . $this->user->getTableName() . " AS a 
165
      ON b.account_id = a.id
166
      WHERE confirmations > 0
167
      GROUP BY finder
168
      ORDER BY solvedblocks DESC LIMIT ?");
169
    if ($this->checkStmt($stmt) && $stmt->bind_param("i", $limit) && $stmt->execute() && $result = $stmt->get_result())
170
      return $this->memcache->setCache(__FUNCTION__ . $limit, $result->fetch_all(MYSQLI_ASSOC), 5);
171
    return $this->sqlError();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sqlError(); (boolean) is incompatible with the return type documented by Statistics::getBlocksSolvedbyAccount of type array.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
172
  }
173
174
  /**
175
   * Get SUM of blocks found and generated Coins for each worker
176
   * @param limit int Last limit blocks
177
   * @return array
178
   **/
179
  public function getBlocksSolvedbyWorker($account_id, $limit=25) {
180
    $this->debug->append("STA " . __METHOD__, 4);
181
    if ($data = $this->memcache->get(__FUNCTION__ . $account_id . $limit)) return $data;
182
    $stmt = $this->mysqli->prepare("
183
      SELECT
184
      	worker_name AS finder,
185
        COUNT(id) AS solvedblocks, 
186
        SUM(amount) AS generatedcoins
187
      FROM " . $this->block->getTableName() . "
188
      WHERE account_id = ? AND worker_name != 'unknown'
189
      GROUP BY finder
190
      ORDER BY solvedblocks DESC LIMIT ?");
191 View Code Duplication
    if ($this->checkStmt($stmt) && $stmt->bind_param("ii", $account_id, $limit) && $stmt->execute() && $result = $stmt->get_result())
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
192
      return $this->memcache->setCache(__FUNCTION__ . $account_id . $limit, $result->fetch_all(MYSQLI_ASSOC), 5);
193
    return $this->sqlError();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sqlError(); (boolean) is incompatible with the return type documented by Statistics::getBlocksSolvedbyWorker of type array.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
194
  }
195
196
  /**
197
   * Currently the only function writing to the database
198
   * Stored per block user statistics of valid and invalid shares
199
   * @param aStats array Array with user id, valid and invalid shares
200
   * @param iBlockId int Block ID as store in the Block table
201
   * @return bool
202
   **/
203
  public function updateShareStatistics($aStats, $iBlockId) {
204
    $this->debug->append("STA " . __METHOD__, 4);
205
    $stmt = $this->mysqli->prepare("INSERT INTO $this->table (account_id, valid, invalid, block_id) VALUES (?, ?, ?, ?)");
206
    if ($this->checkStmt($stmt) && $stmt->bind_param('iddi', $aStats['id'], $aStats['valid'], $aStats['invalid'], $iBlockId) && $stmt->execute()) return true;
207
    return $this->sqlError();
208
  }
209
210
  /**
211
   * insert user round and pplns shares merged array
212
   **/
213
  public function insertPPLNSStatistics($aStats, $iBlockId) {
214
    $this->debug->append("STA " . __METHOD__, 4);
215
    $stmt = $this->mysqli->prepare("INSERT INTO $this->table (account_id, valid, invalid, pplns_valid, pplns_invalid, block_id) VALUES (?, ?, ?, ?, ?, ?)");
216
    if ($this->checkStmt($stmt) && $stmt->bind_param('iddddi', $aStats['id'], $aStats['valid'], $aStats['invalid'], $aStats['pplns_valid'], $aStats['pplns_invalid'], $iBlockId) && $stmt->execute()) return true;
217
    return $this->sqlError();
218
  }
219
220
  /**
221
   * Get our current pool hashrate for the past 10 minutes across both
222
   * shares and shares_archive table
223
   * @param none
224
   * @return data object Return our hashrateas an object
225
   **/
226
  public function getCurrentHashrate($interval=180) {
227
    $this->debug->append("STA " . __METHOD__, 4);
228
    if ($this->getGetCache() && $data = $this->memcache->getStatic(__FUNCTION__)) return $data;
229
    $stmt = $this->mysqli->prepare("
230
      SELECT
231
      (
232
        (
233
          SELECT IFNULL(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS shares
0 ignored issues
show
Bug introduced by
The property config 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...
234
          FROM " . $this->share->getTableName() . "
0 ignored issues
show
Bug introduced by
The property share 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...
235
          WHERE time > DATE_SUB(now(), INTERVAL ? SECOND)
236
          AND our_result = 'Y'
237
        ) + (
238
          SELECT IFNULL(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS shares
239
          FROM " . $this->share->getArchiveTableName() . "
240
          WHERE time > DATE_SUB(now(), INTERVAL ? SECOND)
241
          AND our_result = 'Y'
242
        )
243
      ) AS shares
244
      FROM DUAL");
245
    if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $interval, $interval) && $stmt->execute() && $result = $stmt->get_result() ) {
246
      $hashrate = $this->coin->calcHashrate($result->fetch_object()->shares, $interval);
247
      return $this->memcache->setStaticCache(__FUNCTION__, $hashrate);
248
    }
249
    return $this->sqlError();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sqlError(); (boolean) is incompatible with the return type documented by Statistics::getCurrentHashrate of type data.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
250
  }
251
252
  /**
253
   * Same as getCurrentHashrate but for Shares
254
   * @param none
255
   * @return data object Our share rate in shares per second
256
   **/
257 View Code Duplication
  public function getCurrentShareRate($interval=180) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
258
    $this->debug->append("STA " . __METHOD__, 4);
259
    if ($data = $this->memcache->getStatic(__FUNCTION__)) return $data;
260
    $stmt = $this->mysqli->prepare("
261
      SELECT
262
      (
263
        (
264
          SELECT ROUND(SUM(difficulty) / ?, " . $this->coin->getShareDifficultyPrecision() . ") AS sharerate
265
          FROM " . $this->share->getTableName() . "
266
          WHERE time > DATE_SUB(now(), INTERVAL ? SECOND)
267
          AND our_result = 'Y'
268
        ) + (
269
          SELECT ROUND(SUM(difficulty) / ?, " . $this->coin->getShareDifficultyPrecision() . ") AS sharerate
270
          FROM " . $this->share->getArchiveTableName() . "
271
          WHERE time > DATE_SUB(now(), INTERVAL ? SECOND)
272
          AND our_result = 'Y'
273
        )
274
      ) AS sharerate
275
      FROM DUAL");
276
    if ($this->checkStmt($stmt) && $stmt->bind_param('iiii', $interval, $interval, $interval, $interval) && $stmt->execute() && $result = $stmt->get_result() ) return $this->memcache->setStaticCache(__FUNCTION__, $result->fetch_object()->sharerate);
277
    return $this->sqlError();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sqlError(); (boolean) is incompatible with the return type documented by Statistics::getCurrentShareRate of type data.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
278
  }
279
280
  /**
281
   * Get total shares for this round, since last block found
282
   * @param none
283
   * @return data array invalid and valid shares
284
   **/
285
  public function getRoundShares() {
286
    $this->debug->append("STA " . __METHOD__, 4);
287
    // Try the statistics cron cache, then function cache, then fallback to SQL
288
    if ($data = $this->memcache->get(STATISTICS_ALL_USER_SHARES)) {
289
      $this->debug->append("Found data in statistics cache", 2);
290
      $total = array('valid' => 0, 'invalid' => 0);
291
      foreach ($data['data'] as $aUser) {
292
        $total['valid'] += $aUser['valid'];
293
        $total['invalid'] += $aUser['invalid'];
294
      }
295
      return $total;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $total; (array) is incompatible with the return type documented by Statistics::getRoundShares of type data.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
296
    }
297
    if ($data = $this->memcache->get(STATISTICS_ROUND_SHARES)) {
298
      $this->debug->append("Found data in local cache", 2);
299
      return $data;
300
    }
301
    $stmt = $this->mysqli->prepare("
302
      SELECT
303
        IFNULL(SUM(IF(our_result='Y', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) AS valid,
304
        IFNULL(SUM(IF(our_result='N', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) AS invalid
305
      FROM " . $this->share->getTableName() . "
306
      WHERE UNIX_TIMESTAMP(time) > IFNULL((SELECT MAX(time) FROM " . $this->block->getTableName() . "), 0)");
307
    if ( $this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result() )
308
      return $this->memcache->setCache(STATISTICS_ROUND_SHARES, $result->fetch_assoc());
309
    return $this->sqlError();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sqlError(); (boolean) is incompatible with the return type documented by Statistics::getRoundShares of type data.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
310
  }
311
312
  /**
313
   * Get amount of shares for a all users
314
   * Used in statistics cron to refresh memcache data
315
   * @param account_id int User ID
316
   * @return data array invalid and valid share counts
317
   **/
318
  public function getAllUserShares() {
319
    $this->debug->append("STA " . __METHOD__, 4);
320
    if (! $data = $this->memcache->get(STATISTICS_ALL_USER_SHARES)) {
321
      $data['share_id'] = 0;
322
      $data['data'] = array();
323
    }
324
    $stmt = $this->mysqli->prepare("
325
      SELECT
326
        IFNULL(SUM(IF(our_result='Y', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0) AS valid,
327
        IFNULL(SUM(IF(our_result='N', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0) AS invalid,
328
        u.id AS id,
329
        u.donate_percent AS donate_percent,
330
        u.is_anonymous AS is_anonymous,
331
        u.username AS username
332
      FROM " . $this->share->getTableName() . " AS s,
333
           " . $this->user->getTableName() . " AS u
334
      WHERE u.username = SUBSTRING_INDEX( s.username, '.', 1 )
335
        AND UNIX_TIMESTAMP(s.time) > IFNULL(
336
          (
337
            SELECT MAX(b.time)
338
            FROM " . $this->block->getTableName() . " AS b
339
          ) ,0 )
340
        AND s.id > ?
341
        GROUP BY u.id");
342
    if ($stmt && $stmt->bind_param('i', $data['share_id']) && $stmt->execute() && $result = $stmt->get_result()) {
343
      $data_new = array();
0 ignored issues
show
Unused Code introduced by
$data_new 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...
344
      while ($row = $result->fetch_assoc()) {
345
        if (! array_key_exists($row['id'], $data['data'])) {
346
          $data['data'][$row['id']] = $row;
347
        } else {
348
          $data['data'][$row['id']]['valid'] += $row['valid'];
349
          $data['data'][$row['id']]['invalid'] += $row['invalid'];
350
          $data['data'][$row['id']]['donate_percent'] = $row['donate_percent'];
351
          $data['data'][$row['id']]['is_anonymous'] = $row['is_anonymous'];
352
        }
353
      }
354
      $data['share_id'] = $this->share->getLastInsertedShareId();
355
      return $this->memcache->setCache(STATISTICS_ALL_USER_SHARES, $data);
356
    }
357
    return $this->sqlError();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sqlError(); (boolean) is incompatible with the return type documented by Statistics::getAllUserShares of type data.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
358
  }
359
360
  /**
361
   * Get amount of shares for a specific user
362
   * @param username str username
363
   * @param account_id int account id
364
   * @return data array invalid and valid share counts
365
   **/
366
  public function getUserShares($username, $account_id=NULL) {
367
    $this->debug->append("STA " . __METHOD__, 4);
368
    // Dual-caching, try statistics cron first, then fallback to local, then fallbock to SQL
369
    if ($data = $this->memcache->get(STATISTICS_ALL_USER_SHARES)) {
370
      if (array_key_exists($account_id, $data['data']))
371
        return $data['data'][$account_id];
372
      // We have no cached value, we return defaults
373
      return array('valid' => 0, 'invalid' => 0, 'donate_percent' => 0, 'is_anonymous' => 0);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array('valid' => ..., 'is_anonymous' => 0); (array<string,integer>) is incompatible with the return type documented by Statistics::getUserShares of type data.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
374
    }
375
    if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
376
    $stmt = $this->mysqli->prepare("
377
      SELECT
378
        IFNULL(SUM(IF(our_result='Y', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) AS valid,
379
        IFNULL(SUM(IF(our_result='N', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) AS invalid
380
      FROM " . $this->share->getTableName() . "
381
      WHERE username LIKE ?
382
        AND UNIX_TIMESTAMP(time) >IFNULL((SELECT MAX(b.time) FROM " . $this->block->getTableName() . " AS b),0)");
383
    $username = $username . ".%";   
384
   if ($stmt && $stmt->bind_param("s", $username) && $stmt->execute() && $result = $stmt->get_result())
385
      return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_assoc());
386
    return $this->sqlError();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sqlError(); (boolean) is incompatible with the return type documented by Statistics::getUserShares of type data.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
387
  }
388
389
  /**
390
   * Admin panel specific query
391
   * @return data array User settings and shares
392
   **/
393
  public function getAllUserStats($filter='%',$limit=1,$start=0) {
394
    $this->debug->append("STA " . __METHOD__, 4);
395
    $sql = "
396
      SELECT
397
        a.id AS id,
398
        a.is_admin as is_admin,
399
        a.is_locked as is_locked,
400
        a.no_fees as no_fees,
401
        a.username AS username,
402
        a.donate_percent AS donate_percent,
403
        a.email AS email,
404
        a.last_login as last_login
405
      FROM " . $this->user->getTableName() . " AS a";
406
    if (is_array($filter)) {
407
      $aFilter = array();
408
      foreach ($filter as $key => $value) {
409
        if (isset($value) && $value != "" ) {
410
          switch ($key) {
411
          case 'account':
412
            $aFilter[] = "a.username LIKE ?";
413
            $this->addParam('s', $value);
414
            break;
415
          case 'email':
416
              $aFilter[] = "a.email LIKE ?";
417
              $this->addParam('s', $value);
418
            break;
419
          case 'is_admin':
420
              $aFilter[] = "a.is_admin = ?";
421
              $this->addParam('i', $value);
422
            break;
423
          case 'is_locked':
424
              $aFilter[] = "a.is_locked = ?";
425
              $this->addParam('i', $value);
426
            break;
427
          case 'no_fees':
428
              $aFilter[] = "a.no_fees = ?";
429
              $this->addParam('i', $value);
430
            break;
431
          }
432
        }
433
      }
434
    }
435
    if (!empty($aFilter)) {
436
      $sql .= " WHERE ";
437
      $sql .= implode(' AND ', $aFilter);
438
    }
439
    $sql .= "
440
      ORDER BY username
441
      LIMIT ?,?";
442
    $this->addParam('i', $start);
443
    $this->addParam('i', $limit);
444
    $stmt = $this->mysqli->prepare($sql);
445
    if ($this->checkStmt($stmt) && call_user_func_array( array($stmt, 'bind_param'), $this->getParam()) && $stmt->execute() && $result = $stmt->get_result()) {
446
      // Add our cached shares to the users
447
      $aUsers = array();
448
      while ($row = $result->fetch_assoc()) {
449
        $row['shares'] = $this->getUserShares($row['username'], $row['id']);
450
        $aUsers[] = $row;
451
      }
452
      if (count($aUsers) > 0) {
453
        return $aUsers;
454
      }
455
    }
456
    return $this->sqlError();
457
  }
458
459
  /**
460
   * Fetch all user hashrates based on shares and archived shares
461
   * Store it in cache, also keep a copy of the data internally to
462
   * return it for further processing
463
   * @return data array Set of all user stats
464
   **/
465
  public function fetchAllUserMiningStats($interval=180) {
466
    $this->debug->append("STA " . __METHOD__, 4);
467
    $stmt = $this->mysqli->prepare("
468
      SELECT
469
        a.id AS id,
470
        a.username AS account,
471
        COUNT(DISTINCT t1.username) AS workers,
472
        IFNULL(SUM(t1.difficulty), 0) AS shares,
473
        ROUND(SUM(t1.difficulty) / ?, " . $this->coin->getShareDifficultyPrecision() . ") AS sharerate,
474
        IFNULL(AVG(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS avgsharediff
475
      FROM (
476
        SELECT
477
          id,
478
          IF(difficulty = 0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty) AS difficulty,
479
          username
480
        FROM " . $this->share->getTableName() . "
481
        WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) AND our_result = 'Y'
482
        UNION
483
        SELECT
484
          share_id,
485
          IF(difficulty = 0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty) AS difficulty,
486
          username
487
        FROM " . $this->share->getArchiveTableName() . "
488
        WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) AND our_result = 'Y'
489
      ) AS t1
490
      LEFT JOIN " . $this->user->getTableName() . " AS a
491
      ON SUBSTRING_INDEX( t1.username, '.', 1 ) = a.username
492
      WHERE a.id IS NOT NULL
493
      GROUP BY account
494
      ORDER BY shares DESC
495
      ");
496
    if ($this->checkStmt($stmt) && $stmt->bind_param("iii", $interval, $interval, $interval) && $stmt->execute() && $result = $stmt->get_result() ) {
497
      $aData = array();
498
      while ($row = $result->fetch_assoc()) {
499
        $aData['data'][$row['id']] = $row;
500
        $aData['data'][$row['id']]['hashrate'] = $this->coin->calcHashrate($row['shares'], $interval);
501
      }
502
      $this->allUserMiningStats = $aData;
503
      return $this->memcache->setStaticCache(STATISTICS_ALL_USER_HASHRATES, $aData, 600);
504
    } else {
505
      return $this->sqlError();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sqlError(); (boolean) is incompatible with the return type documented by Statistics::fetchAllUserMiningStats of type data.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
506
    }
507
  }
508
509
  /**
510
   * Store our gathered data into our statistic table for users
511
   * @param aData array Data created by fetchAllUserMiningStats
512
   * @return bool true or false
513
   **/
514
  public function storeAllUserMiningStatsSnapshot($aData) {
515
    $this->debug->append("STA " . __METHOD__, 4);
516
    if (!isset($aData['data'])) return false;
517
    // initilize
518
    $timestamp = time();    // Store all entries with the same timestamp to reduce cardinality
519
    $ok = 0;
520
    $failed = 0;
521
    foreach ($aData['data'] as $key => $aUserData) {
522
      $stmt = $this->mysqli->prepare("
523
        INSERT INTO " . $this->getUserStatsTableName() . "
524
          ( account_id, hashrate, workers, sharerate, timestamp ) VALUES ( ?, ?, ?, ?, ?)");
525
      if ($this->checkStmt($stmt) && $stmt->bind_param("ididi", $aUserData['id'], $aUserData['hashrate'], $aUserData['workers'], $aUserData['sharerate'], $timestamp) && $stmt->execute() ) {
526
        $ok++;
527
      } else {
528
        $failed++;
529
      }
530
    }
531
    return array('ok' => $ok, 'failed' => $failed);
532
  }
533
534
  /**
535
   * Fetch unpaid PPS shares for an account
536
   * @param username string Username
537
   * @param account_id int User ID
538
   * @param last_paid_pps_id int Last paid out share by pps_payout cron
539
   * @return data int Sum of unpaid diff1 shares
540
   **/
541
  public function getUserUnpaidPPSShares($username, $account_id=NULL, $last_paid_pps_id) {
542
    $this->debug->append("STA " . __METHOD__, 4);
543
    if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
544
    $stmt = $this->mysqli->prepare("
545
      SELECT
546
        IFNULL(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS total
547
      FROM " . $this->share->getTableName() . "
548
      WHERE username LIKE ?
549
      AND id > ?
550
      AND our_result = 'Y'");
551
    $username = $username . ".%";
552
    if ($this->checkStmt($stmt) && $stmt->bind_param("si", $username, $last_paid_pps_id) && $stmt->execute() && $result = $stmt->get_result() )
553
      return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_object()->total);
554
    return $this->sqlError();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sqlError(); (boolean) is incompatible with the return type documented by Statistics::getUserUnpaidPPSShares of type data.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
555
  }
556
557
  /**
558
   * Get Shares per x interval by user
559
   * @param username string username
560
   * @param $account_id int account id   
561
   * @return data integer Current Sharerate in diff1 shares/s
562
   **/
563
  public function getUserMiningStats($username, $account_id=NULL, $interval=180) {
564
    $this->debug->append("STA " . __METHOD__, 4);
565
    // Dual-caching, try statistics cron first, then fallback to local, then fallbock to SQL
566
    if ($this->getGetCache() && $data = $this->memcache->getStatic(STATISTICS_ALL_USER_HASHRATES)) {
567
      if (array_key_exists($account_id, $data['data'])) {
568
        $retData['hashrate'] = $data['data'][$account_id]['hashrate'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$retData was never initialized. Although not strictly required by PHP, it is generally a good practice to add $retData = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
569
        $retData['sharerate'] = $data['data'][$account_id]['sharerate'];
570
        $retData['avgsharediff'] = $data['data'][$account_id]['avgsharediff'];
571
        return $retData;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $retData; (array) is incompatible with the return type documented by Statistics::getUserMiningStats of type data.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
572
      }
573
      return array('hashrate' => (float)0, 'sharerate' => (float)0, 'avgsharediff' => (float)0);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array('hashrate' ...rediff' => (double) 0); (array<string,double>) is incompatible with the return type documented by Statistics::getUserMiningStats of type data.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
574
    }
575
    if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
576
    $stmt = $this->mysqli->prepare("
577
      SELECT
578
        IFNULL(SUM(difficulty) / ?, 0) AS sharerate,
579
        IFNULL(SUM(difficulty), 0) AS shares,
580
        IFNULL(AVG(difficulty), 0) AS avgsharediff
581
      FROM (
582
        SELECT
583
          id, our_result, IF(difficulty = 0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty) AS difficulty
584
        FROM
585
          " . $this->share->getTableName() . "
586
        WHERE username LIKE ?
587
          AND time > DATE_SUB(now(), INTERVAL ? SECOND)
588
          AND our_result = 'Y'
589
      UNION
590
        SELECT
591
          share_id, our_result, IF(difficulty = 0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty) AS difficulty
592
        FROM
593
          " . $this->share->getArchiveTableName() . "
594
        WHERE username LIKE ?
595
          AND time > DATE_SUB(now(), INTERVAL ? SECOND)
596
          AND our_result = 'Y'
597
      ) AS temp");
598
    $username = $username . ".%";
599
    if ($this->checkStmt($stmt) && $stmt->bind_param("isisi", $interval, $username, $interval, $username, $interval) && $stmt->execute() && $result = $stmt->get_result() ) {
600
      $aData = $result->fetch_assoc();
601
      $aData['hashrate'] = $this->coin->calcHashrate($aData['shares'], $interval);
602
      return $this->memcache->setCache(__FUNCTION__ . $account_id, $aData);
603
    }
604
    return $this->sqlError();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sqlError(); (boolean) is incompatible with the return type documented by Statistics::getUserMiningStats of type data.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
605
  }
606
607
  /**
608
   * get our top contributors for either shares or hashrate
609
   * @param type string shares or hashes
610
   * @param limit int Limit result to $limit
611
   * @return data array Users with shares, account or hashrate, account
612
   **/
613
  public function getTopContributors($type='shares', $limit=15) {
614
    $this->debug->append("STA " . __METHOD__, 4);
615
    switch ($type) {
616
    case 'shares':
617 View Code Duplication
      if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $type . $limit)) return $data;
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
618
      if ($data = $this->memcache->get(STATISTICS_ALL_USER_SHARES)) {
619
        // Use global cache to build data, if we have any data there
620
        if (!empty($data['data']) && is_array($data['data'])) {
621
          foreach($data['data'] as $key => $aUser) {
622
            $shares[$key] = $aUser['valid'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$shares was never initialized. Although not strictly required by PHP, it is generally a good practice to add $shares = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
623
            $username[$key] = $aUser['username'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$username was never initialized. Although not strictly required by PHP, it is generally a good practice to add $username = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
624
          }
625
          array_multisort($shares, SORT_DESC, $username, SORT_ASC, $data['data']);
0 ignored issues
show
Bug introduced by
The variable $username does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
626
          $count = 0;
627
          foreach ($data['data'] as $key => $aUser) {
628
            if ($count == $limit) break;
629
            $count++;
630
            $data_new[$key]['shares'] = $aUser['valid'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$data_new was never initialized. Although not strictly required by PHP, it is generally a good practice to add $data_new = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
631
            $data_new[$key]['account'] = $aUser['username'];
632
            $data_new[$key]['donate_percent'] = $aUser['donate_percent'];
633
            $data_new[$key]['is_anonymous'] = $aUser['is_anonymous'];
634
          }
635
          return $data_new;
0 ignored issues
show
Bug introduced by
The variable $data_new does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
636
        }
637
      }
638
      // No cached data, fallback to SQL ONLY if we don't use memcache
639
      if ($this->config['memcache']['enabled'] && $this->config['memcache']['force']['contrib_shares']) {
640
        // Do not use SQL queries and a second layer of caching
641
        $this->debug->append('Skipping SQL queries due to config option', 4);
642
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Statistics::getTopContributors of type data.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
643
      }
644
      $stmt = $this->mysqli->prepare("
645
        SELECT
646
          a.username AS account,
647
          a.donate_percent AS donate_percent,
648
          a.is_anonymous AS is_anonymous,
649
          IFNULL(SUM(IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)), 0) AS shares
650
        FROM " . $this->share->getTableName() . " AS s
651
        LEFT JOIN " . $this->user->getTableName() . " AS a
652
        ON SUBSTRING_INDEX( s.username, '.', 1 ) = a.username
653
        WHERE our_result = 'Y'
654
        GROUP BY account
655
        ORDER BY shares DESC
656
        LIMIT ?");
657
      if ($this->checkStmt($stmt) && $stmt->bind_param("i", $limit) && $stmt->execute() && $result = $stmt->get_result())
658
        return $this->memcache->setCache(__FUNCTION__ . $type . $limit, $result->fetch_all(MYSQLI_ASSOC));
659
      return $this->sqlError();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sqlError(); (boolean) is incompatible with the return type documented by Statistics::getTopContributors of type data.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
660
      break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
661
662
    case 'hashes':
663 View Code Duplication
      if ($this->getGetCache() && $data = $this->memcache->getStatic(__FUNCTION__ . $type . $limit)) return $data;
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
664
      $stmt = $this->mysqli->prepare("
665
         SELECT
666
          a.username AS account,
667
          a.donate_percent AS donate_percent,
668
          a.is_anonymous AS is_anonymous,
669
          IFNULL(SUM(t1.difficulty), 0) AS shares
670
        FROM
671
        (
672
          SELECT id, IFNULL(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0) AS difficulty, username FROM " . $this->share->getTableName() . " WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE) AND our_result = 'Y'
673
          UNION
674
          SELECT share_id, IFNULL(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0) AS difficulty, username FROM " . $this->share->getArchiveTableName() ." WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE) AND our_result = 'Y'
675
        ) AS t1
676
        LEFT JOIN " . $this->user->getTableName() . " AS a
677
        ON SUBSTRING_INDEX( t1.username, '.', 1 ) = a.username
678
        GROUP BY account
679
        ORDER BY shares DESC LIMIT ?");
680
      if ($this->checkStmt($stmt) && $stmt->bind_param("i", $limit) && $stmt->execute() && $result = $stmt->get_result()) {
681
        $aData = array();
682
        $count = 0;
683
        while ($row = $result->fetch_assoc()) {
684
          $aData[$count] = $row;
685
          $aData[$count]['hashrate'] = $this->coin->calcHashrate($row['shares'], 600);
686
          $count++;
687
        }
688
        return $this->memcache->setStaticCache(__FUNCTION__ . $type . $limit, $aData);
689
      }
690
      return $this->sqlError();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sqlError(); (boolean) is incompatible with the return type documented by Statistics::getTopContributors of type data.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
691
      break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
692
    }
693
  }
694
695
  /**
696
   * get Hourly hashrate for a user
697
   * @param username string Username
698
   * @param $account_id int account id
699
   * @return data array NOT FINISHED YET
700
   **/
701
  public function getHourlyMiningStatsByAccount($account_id, $format='array', $days = 1) {
702
    $this->debug->append("STA " . __METHOD__, 4);
703
    if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
704
    $stmt = $this->mysqli->prepare("
705
      SELECT
706
        timestamp,
707
        FROM_UNIXTIME(timestamp, '%Y-%m-%d %H:%i') AS time,
708
        AVG(hashrate) AS hashrate,
709
        AVG(workers) AS workers,
710
        AVG(sharerate) AS sharerate
711
      FROM " . $this->getUserStatsTableName() . "
712
      WHERE FROM_UNIXTIME(timestamp) >= DATE_SUB(NOW(), INTERVAL $days DAY)
713
        AND account_id = ?
714
      GROUP BY DAY(FROM_UNIXTIME(timestamp)), HOUR(FROM_UNIXTIME(timestamp))");
715
    if ($this->checkStmt($stmt) && $stmt->bind_param('i', $account_id) && $stmt->execute() && $result = $stmt->get_result()) {
716
      $aData = $result->fetch_all(MYSQLI_ASSOC);
717
      if ($format == 'json') $aData = json_encode($aData);
718
      return $this->memcache->setCache(__FUNCTION__ . $account_id . $format, $aData);
719
    }
720
    return $this->sqlError();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sqlError(); (boolean) is incompatible with the return type documented by Statistics::getHourlyMiningStatsByAccount of type data.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
721
  }
722
723
  /**
724
   * get user estimated payouts based on share counts
725
   * @param value1 mixed Round shares OR share rate
726
   * @param value2 mixed User shares OR share difficulty
727
   * @param dDonate double User donation setting
728
   * @param bNoFees bool User no-fees option setting
729
   * @return aEstimates array User estimations
730
   **/
731
  public function getUserEstimates($value1, $value2, $dDonate, $bNoFees, $ppsvalue=0) {
732
    $this->debug->append("STA " . __METHOD__, 4);
733
    if ($this->config['payout_system'] != 'pps') {
734
      if (@$value1['valid'] > 0  && @$value2['valid'] > 0) {
735
        $this->config['reward_type'] == 'fixed' ? $reward = $this->config['reward'] : $reward = $this->block->getAverageAmount();
736
        $aEstimates['block'] = round(( (float)$value2['valid'] / (float)$value1['valid'] ) * (float)$reward, 8);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$aEstimates was never initialized. Although not strictly required by PHP, it is generally a good practice to add $aEstimates = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
737
        $bNoFees == 0 ? $aEstimates['fee'] = round(((float)$this->config['fees'] / 100) * (float)$aEstimates['block'], 8) : $aEstimates['fee'] = 0;
738
        $aEstimates['donation'] = round((( (float)$dDonate / 100) * ((float)$aEstimates['block'] - (float)$aEstimates['fee'])), 8);
739
        $aEstimates['payout'] = round((float)$aEstimates['block'] - (float)$aEstimates['donation'] - (float)$aEstimates['fee'], 8);
740
      } else {
741
        $aEstimates['block'] = 0;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$aEstimates was never initialized. Although not strictly required by PHP, it is generally a good practice to add $aEstimates = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
742
        $aEstimates['fee'] = 0;
743
        $aEstimates['donation'] = 0;
744
        $aEstimates['payout'] = 0;
745
      }
746
    } else {
747
      // Hack so we can use this method for PPS estimates too
748
      // value1 = shares/s
749
      // value2 = avg share difficulty
750
      if (@$value1 > 0 && @$value2 > 0) {
751
        $hour = 60 * 60;
752
        $pps = $value1 * $value2 * $ppsvalue;
753
        $aEstimates['hours1'] = $pps * $hour;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$aEstimates was never initialized. Although not strictly required by PHP, it is generally a good practice to add $aEstimates = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
754
        $aEstimates['hours24'] = $pps * 24 * $hour;
755
        $aEstimates['days7'] = $pps * 24 * 7 * $hour;
756
        $aEstimates['days14'] = $pps * 14 * 24 * $hour;
757
        $aEstimates['days30'] = $pps * 30 * 24 * $hour;
758
      } else {
759
        $aEstimates['hours1'] = 0;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$aEstimates was never initialized. Although not strictly required by PHP, it is generally a good practice to add $aEstimates = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
760
        $aEstimates['hours24'] = 0;
761
        $aEstimates['days7'] = 0;
762
        $aEstimates['days14'] = 0;
763
        $aEstimates['days30'] = 0;
764
      }
765
    }
766
    return $aEstimates;
767
  }
768
769
  /**
770
   * Get pool stats last 24 hours
771
   * @param limit int Last number of hours
772
   * @return array
773
   **/
774
  public function getPoolStatsHours($hour=24) {
775
    $this->debug->append("STA " . __METHOD__, 4);
776
    if ($data = $this->memcache->get(__FUNCTION__ . $hour)) return $data;
777
    $stmt = $this->mysqli->prepare("
778
      SELECT
779
      IFNULL(COUNT(id), 0) as count,
780
      IFNULL(AVG(difficulty), 0) as average,
781
      IFNULL(SUM(shares), 0) as shares,
782
      IFNULL(SUM(amount), 0) as rewards
783
      FROM " . $this->block->getTableName() . "
784
      WHERE FROM_UNIXTIME(time) > DATE_SUB(now(), INTERVAL ? HOUR)
785
      AND confirmations >= 1");
786
    if ($this->checkStmt($stmt) && $stmt->bind_param("i", $hour) && $stmt->execute() && $result = $stmt->get_result()) {
787
      $aData = $result->fetch_assoc();
788
      $aData['expected'] = $this->coin->calcEstaimtedShares($aData['average']);
789
      return $this->memcache->setCache(__FUNCTION__ . $hour, $aData);
790
    }
791
    return $this->sqlError();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sqlError(); (boolean) is incompatible with the return type documented by Statistics::getPoolStatsHours of type array.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
792
  }
793
794
  /**
795
   * Caclulate estimated shares based on network difficulty and pool difficulty
796
   * @param dDiff double Network difficulty
797
   * @return shares integer Share count
798
   **/
799
  public function getEstimatedShares($dDiff) {
800
    return $this->coin->calcEstaimtedShares($dDiff);
801
  }
802
803
  /**
804
   * Get the Expected Time per Block in the whole Network in seconde
805
   * @return seconds double Seconds per Block
806
   */
807
  public function getExpectedTimePerBlock($type='network',$hashrate = 0){
808
    if ($data = $this->memcache->get(__FUNCTION__)) return $data;
809
810
    if ($this->bitcoin->can_connect() === true) {
811
      if ($type == 'network') {
812
        $hashrate = $this->bitcoin->getnetworkhashps();
0 ignored issues
show
Bug introduced by
The property bitcoin 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...
813
      } else {
814
        // We need hashes/second and expect khash as input
815
        $hashrate = $hashrate * 1000;
816
      }
817
      $dDifficulty = $this->bitcoin->getdifficulty();
818
    } else {
819
      $hashrate = 1;
820
      $dDifficulty = 1;
821
    }
822
    if ($hashrate <= 0) $hashrate = 1;
823
    return $this->memcache->setCache(__FUNCTION__ . '_' . $type, $this->coin->calcNetworkExpectedTimePerBlock($dDifficulty, $hashrate));
824
  }
825
826
  /**
827
   * Get the Expected next Difficulty
828
   * @return difficulty double Next difficulty
829
   **/
830
  public function getExpectedNextDifficulty(){
831
    if ($data = $this->memcache->get(__FUNCTION__)) return $data;
832
833
    if ($this->bitcoin->can_connect() === true) {
834
      $dDifficulty = $this->bitcoin->getdifficulty();
835
      $dNetworkHashrate = $this->bitcoin->getnetworkhashps();
836
    } else {
837
      $dDifficulty = 1;
838
      $dNetworkHashrate = 1;
839
    }
840
841
    return $this->memcache->setCache(__FUNCTION__, $this->coin->calcExpectedNextDifficulty($dDifficulty, $dNetworkHashrate));
842
  }
843
844
  /**
845
   * Get Number of blocks until next difficulty change
846
   * @return blocks int blocks until difficulty change
847
   **/
848
  public function getBlocksUntilDiffChange(){
849
    if ($data = $this->memcache->get(__FUNCTION__)) return $data;
850
851
    if ($this->bitcoin->can_connect() === true) {
852
      $iBlockcount = $this->bitcoin->getblockcount();
853
    } else {
854
      $iBlockcount = 1;
855
    }
856
857
    return $this->memcache->setCache(__FUNCTION__, $this->config['coindiffchangetarget'] - ($iBlockcount % $this->config['coindiffchangetarget']));
858
  }
859
860
  /**
861
   * Get current PPS value
862
   * @return value double PPS Value
863
   **/
864
865
  public function getPPSValue() {
866
    // Fetch RPC difficulty
867
    if ($this->bitcoin->can_connect() === true) {
868
      $dDifficulty = $this->bitcoin->getdifficulty();
869
    } else {
870
      $dDifficulty = 1;
871
    }
872
873
    if ($this->config['pps']['reward']['type'] == 'blockavg' && $this->block->getBlockCount() > 0) {
874
      $pps_reward = round($this->block->getAvgBlockReward($this->config['pps']['blockavg']['blockcount']));
875
    } else {
876
      if ($this->config['pps']['reward']['type'] == 'block') {
877
        if ($aLastBlock = $this->block->getLast()) {
878
          $pps_reward = $aLastBlock['amount'];
879
        } else {
880
          $pps_reward = $this->config['pps']['reward']['default'];
881
        }
882
      } else {
883
        $pps_reward = $this->config['pps']['reward']['default'];
884
      }
885
    }
886
    return round($this->coin->calcPPSValue($pps_reward, $dDifficulty), 12);
887
  }
888
889
  /**
890
   * Get all currently active users in the past 2 minutes
891
   * @param interval int Time in seconds to fetch shares from
892
   * @return data mixed int count if any users are active, false otherwise
893
   **/
894 View Code Duplication
  public function getCountAllActiveUsers($interval=120) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
895
    $this->debug->append("STA " . __METHOD__, 4);
896
    if ($data = $this->memcache->get(__FUNCTION__)) return $data;
897
    $stmt = $this->mysqli->prepare("
898
      SELECT COUNT(DISTINCT(SUBSTRING_INDEX( `username` , '.', 1 ))) AS total
899
      FROM "  . $this->share->getTableName() . "
900
      WHERE our_result = 'Y'
901
      AND time > DATE_SUB(now(), INTERVAL ? SECOND)");
902
    if ($this->checkStmt($stmt) && $stmt->bind_param('i', $interval) && $stmt->execute() && $result = $stmt->get_result())
903
      return $this->memcache->setCache(__FUNCTION__, $result->fetch_object()->total);
904
    return $this->sqlError();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sqlError(); (boolean) is incompatible with the return type documented by Statistics::getCountAllActiveUsers of type data.

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

Let’s take a look at an example:

class Author {
    private $name;

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

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

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

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

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

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

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

Loading history...
905
  }
906
907
  /**
908
   * Purge older entries from our statistics_users table
909
   **/
910
  public function purgeUserStats($days = 1) {
911
    // Fallbacks if unset
912
    $stmt = $this->mysqli->prepare("DELETE FROM " . $this->getUserStatsTableName() . " WHERE FROM_UNIXTIME(timestamp) <= DATE_SUB(NOW(), INTERVAL ? DAY)");
913
    if ($this->checkStmt($stmt) && $stmt->bind_param('i', $days) && $stmt->execute())
914
      return $stmt->affected_rows;
915
    return $this->sqlError();
916
  }
917
}
918
919
$statistics = new Statistics();
920
$statistics->setDebug($debug);
921
$statistics->setMysql($mysqli);
922
$statistics->setShare($share);
923
$statistics->setUser($user);
924
$statistics->setBlock($block);
925
$statistics->setMemcache($memcache);
926
$statistics->setConfig($config);
927
$statistics->setBitcoin($bitcoin);
928
$statistics->setErrorCodes($aErrorCodes);
929
$statistics->setCoin($coin);
930