This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; |
||
3 | |||
4 | class Transaction extends Base { |
||
5 | protected $table = 'transactions'; |
||
6 | public $num_rows = 0, $insert_id = 0; |
||
7 | |||
8 | /** |
||
9 | * Add a new transaction to our class table |
||
10 | * We also store the inserted ID in case the user needs it |
||
11 | * @param account_id int Account ID to book transaction for |
||
12 | * @param amount float Coin amount |
||
13 | * @param type string Transaction type [Credit, Debit_AP, Debit_MP, Fee, Donation, Orphan_Credit, Orphan_Fee, Orphan_Donation] |
||
14 | * @param block_id int Block ID to link transaction to [optional] |
||
15 | * @param coin_address string Coin address for this transaction [optional] |
||
16 | * @return bool |
||
17 | **/ |
||
18 | public function addTransaction($account_id, $amount, $type='Credit', $block_id=NULL, $coin_address=NULL, $txid=NULL) { |
||
19 | $amount = number_format($amount, $this->coin->getCoinValuePrevision(), '.', ''); |
||
0 ignored issues
–
show
|
|||
20 | $stmt = $this->mysqli->prepare("INSERT INTO $this->table (account_id, amount, block_id, type, coin_address, txid) VALUES (?, ?, ?, ?, ?, ?)"); |
||
21 | if ($this->checkStmt($stmt) && $stmt->bind_param("isisss", $account_id, $amount, $block_id, $type, $coin_address, $txid) && $stmt->execute()) { |
||
22 | $this->insert_id = $stmt->insert_id; |
||
23 | return true; |
||
24 | } |
||
25 | return $this->sqlError(); |
||
26 | } |
||
27 | |||
28 | /** |
||
29 | * Update a transaction with a RPC transaction ID |
||
30 | * @param id integer Transaction ID |
||
31 | * @param txid string RPC Transaction Identifier |
||
32 | * @return bool true or false |
||
33 | **/ |
||
34 | public function setRPCTxId($transaction_id, $rpc_txid=NULL) { |
||
35 | $stmt = $this->mysqli->prepare("UPDATE $this->table SET txid = ? WHERE id = ?"); |
||
36 | if ($this->checkStmt($stmt) && $stmt->bind_param('si', $rpc_txid, $transaction_id) && $stmt->execute()) |
||
37 | return true; |
||
38 | return $this->sqlError(); |
||
39 | } |
||
40 | |||
41 | /* |
||
42 | * Mark transactions of a user as archived |
||
43 | * @param account_id int Account ID |
||
44 | * @param txid int Transaction ID to start from |
||
45 | * @param bool boolean True or False |
||
46 | **/ |
||
47 | View Code Duplication | public function setArchived($account_id, $txid) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
48 | // Update all paid out transactions as archived |
||
49 | $stmt = $this->mysqli->prepare(" |
||
50 | UPDATE $this->table AS t |
||
51 | LEFT JOIN " . $this->block->getTableName() . " AS b |
||
0 ignored issues
–
show
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;
![]() |
|||
52 | ON b.id = t.block_id |
||
53 | SET t.archived = 1 |
||
54 | WHERE t.archived = 0 |
||
55 | AND ( |
||
56 | ( t.account_id = ? AND t.id <= ? AND b.confirmations >= ? ) |
||
57 | OR ( t.account_id = ? AND t.id <= ? AND b.confirmations = -1 ) |
||
58 | OR ( t.account_id = ? AND t.id <= ? AND t.type IN ( 'Credit_PPS', 'Donation_PPS', 'Fee_PPS', 'TXFee', 'Debit_MP', 'Debit_AP' ) ) |
||
59 | )"); |
||
60 | if ($this->checkStmt($stmt) && $stmt->bind_param('iiiiiii', $account_id, $txid, $this->config['confirmations'], $account_id, $txid, $account_id, $txid) && $stmt->execute()) |
||
0 ignored issues
–
show
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;
![]() |
|||
61 | return true; |
||
62 | return $this->sqlError(); |
||
63 | } |
||
64 | |||
65 | /** |
||
66 | * Fetch a transaction summary by type with total amounts |
||
67 | * @param account_id int Account ID, NULL for all |
||
68 | * @return data array type and total |
||
69 | **/ |
||
70 | public function getTransactionSummary($account_id=NULL) { |
||
71 | if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; |
||
0 ignored issues
–
show
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;
![]() |
|||
72 | $sql = " |
||
73 | SELECT |
||
74 | SUM(t.amount) AS total, t.type AS type |
||
75 | FROM $this->table AS t |
||
76 | LEFT OUTER JOIN " . $this->block->getTableName() . " AS b |
||
77 | ON b.id = t.block_id |
||
78 | WHERE ( b.confirmations > 0 OR b.id IS NULL )"; |
||
79 | if (!empty($account_id)) { |
||
80 | $sql .= " AND t.account_id = ? "; |
||
81 | $this->addParam('i', $account_id); |
||
82 | } |
||
83 | $sql .= " GROUP BY t.type"; |
||
84 | $stmt = $this->mysqli->prepare($sql); |
||
85 | if (!empty($account_id)) { |
||
86 | View Code Duplication | if (!($this->checkStmt($stmt) && call_user_func_array( array($stmt, 'bind_param'), $this->getParam()) && $stmt->execute())) |
|
0 ignored issues
–
show
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. ![]() |
|||
87 | return false; |
||
0 ignored issues
–
show
The return type of
return false; (false ) is incompatible with the return type documented by Transaction::getTransactionSummary 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 ![]() |
|||
88 | $result = $stmt->get_result(); |
||
89 | } else { |
||
90 | if (!($this->checkStmt($stmt) && $stmt->execute())) |
||
91 | return false; |
||
0 ignored issues
–
show
The return type of
return false; (false ) is incompatible with the return type documented by Transaction::getTransactionSummary 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 ![]() |
|||
92 | $result = $stmt->get_result(); |
||
93 | } |
||
94 | if ($result) { |
||
95 | $aData = NULL; |
||
96 | while ($row = $result->fetch_assoc()) { |
||
97 | $aData[$row['type']] = $row['total']; |
||
98 | } |
||
99 | // Cache data for a while, query takes long on many rows |
||
100 | return $this->memcache->setCache(__FUNCTION__ . $account_id, $aData, 60); |
||
101 | } |
||
102 | return $this->sqlError(); |
||
0 ignored issues
–
show
The return type of
return $this->sqlError(); (boolean ) is incompatible with the return type documented by Transaction::getTransactionSummary 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 ![]() |
|||
103 | } |
||
104 | |||
105 | |||
106 | /** |
||
107 | * Fetch a transaction summary by user with total amounts |
||
108 | * @param account_id int Account ID, NULL for all |
||
109 | * @return data array type and total |
||
110 | **/ |
||
111 | View Code Duplication | public function getTransactionTypebyTime($account_id=NULL) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
112 | $this->debug->append("STA " . __METHOD__, 4); |
||
113 | if ($data = $this->memcache->get(__FUNCTION__)) return $data; |
||
114 | $stmt = $this->mysqli->prepare(" |
||
115 | SELECT |
||
116 | IFNULL(SUM(IF(t.type = 'Credit' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourCredit, |
||
117 | IFNULL(SUM(IF(t.type = 'Bonus' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourBonus, |
||
118 | IFNULL(SUM(IF(t.type = 'Debit_MP' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourDebitMP, |
||
119 | IFNULL(SUM(IF(t.type = 'Debit_AP' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourDebitAP, |
||
120 | IFNULL(SUM(IF(t.type = 'TXFee' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourTXFee, |
||
121 | IFNULL(SUM(IF(t.type = 'Fee' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourFee, |
||
122 | IFNULL(SUM(IF(t.type = 'Donation' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourDonation, |
||
123 | |||
124 | IFNULL(SUM(IF(t.type = 'Credit' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourCredit, |
||
125 | IFNULL(SUM(IF(t.type = 'Bonus' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourBonus, |
||
126 | IFNULL(SUM(IF(t.type = 'Debit_MP' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourDebitMP, |
||
127 | IFNULL(SUM(IF(t.type = 'Debit_AP' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourDebitAP, |
||
128 | IFNULL(SUM(IF(t.type = 'TXFee' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourTXFee, |
||
129 | IFNULL(SUM(IF(t.type = 'Fee' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourFee, |
||
130 | IFNULL(SUM(IF(t.type = 'Donation' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourDonation, |
||
131 | |||
132 | IFNULL(SUM(IF(t.type = 'Credit' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekCredit, |
||
133 | IFNULL(SUM(IF(t.type = 'Bonus' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekBonus, |
||
134 | IFNULL(SUM(IF(t.type = 'Debit_MP' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekDebitMP, |
||
135 | IFNULL(SUM(IF(t.type = 'Debit_AP' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekDebitAP, |
||
136 | IFNULL(SUM(IF(t.type = 'TXFee' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekTXFee, |
||
137 | IFNULL(SUM(IF(t.type = 'Fee' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekFee, |
||
138 | IFNULL(SUM(IF(t.type = 'Donation' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekDonation, |
||
139 | |||
140 | IFNULL(SUM(IF(t.type = 'Credit' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthCredit, |
||
141 | IFNULL(SUM(IF(t.type = 'Bonus' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthBonus, |
||
142 | IFNULL(SUM(IF(t.type = 'Debit_MP' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthDebitMP, |
||
143 | IFNULL(SUM(IF(t.type = 'Debit_AP' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthDebitAP, |
||
144 | IFNULL(SUM(IF(t.type = 'TXFee' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthTXFee, |
||
145 | IFNULL(SUM(IF(t.type = 'Fee' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthFee, |
||
146 | IFNULL(SUM(IF(t.type = 'Donation' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthDonation, |
||
147 | |||
148 | IFNULL(SUM(IF(t.type = 'Credit' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearCredit, |
||
149 | IFNULL(SUM(IF(t.type = 'Bonus' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearBonus, |
||
150 | IFNULL(SUM(IF(t.type = 'Debit_MP' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearDebitMP, |
||
151 | IFNULL(SUM(IF(t.type = 'Debit_AP' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearDebitAP, |
||
152 | IFNULL(SUM(IF(t.type = 'TXFee' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearTXFee, |
||
153 | IFNULL(SUM(IF(t.type = 'Fee' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearFee, |
||
154 | IFNULL(SUM(IF(t.type = 'Donation' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearDonation |
||
155 | FROM $this->table AS t |
||
156 | LEFT OUTER JOIN " . $this->block->getTableName() . " AS b ON b.id = t.block_id |
||
157 | WHERE |
||
158 | t.account_id = ? AND (b.confirmations > 0 OR b.id IS NULL)"); |
||
159 | if ($this->checkStmt($stmt) && $stmt->bind_param("i", $account_id) && $stmt->execute() && $result = $stmt->get_result()) |
||
160 | return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_assoc(), 60); |
||
161 | return $this->sqlError(); |
||
0 ignored issues
–
show
The return type of
return $this->sqlError(); (boolean ) is incompatible with the return type documented by Transaction::getTransactionTypebyTime 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 ![]() |
|||
162 | } |
||
163 | |||
164 | /** |
||
165 | * Get all transactions from start for account_id |
||
166 | * @param start int Starting point, id of transaction |
||
167 | * @param filter array Filter to limit transactions |
||
168 | * @param limit int Only display this many transactions |
||
169 | * @param account_id int Account ID |
||
170 | * @return data array Database fields as defined in SELECT |
||
171 | **/ |
||
172 | public function getTransactions($start=0, $filter=NULL, $limit=30, $account_id=NULL) { |
||
173 | $this->debug->append("STA " . __METHOD__, 4); |
||
174 | $sql = " |
||
175 | SELECT |
||
176 | t.id AS id, |
||
177 | a.username as username, |
||
178 | t.type AS type, |
||
179 | t.amount AS amount, |
||
180 | t.coin_address AS coin_address, |
||
181 | t.timestamp AS timestamp, |
||
182 | t.txid AS txid, |
||
183 | b.height AS height, |
||
184 | b.blockhash AS blockhash, |
||
185 | b.confirmations AS confirmations |
||
186 | FROM $this->table AS t |
||
187 | LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id |
||
188 | LEFT JOIN " . $this->user->getTableName() . " AS a ON t.account_id = a.id"; |
||
0 ignored issues
–
show
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;
![]() |
|||
189 | if (!empty($account_id)) { |
||
190 | $sql .= " WHERE ( t.account_id = ? ) "; |
||
191 | $this->addParam('i', $account_id); |
||
192 | } |
||
193 | if (is_array($filter)) { |
||
194 | $aFilter = array(); |
||
195 | foreach ($filter as $key => $value) { |
||
196 | if (!empty($value)) { |
||
197 | switch ($key) { |
||
198 | case 'type': |
||
199 | $aFilter[] = "( t.type = ? )"; |
||
200 | $this->addParam('s', $value); |
||
201 | break; |
||
202 | case 'status': |
||
203 | switch ($value) { |
||
204 | case 'Confirmed': |
||
205 | if (empty($filter['type']) || ($filter['type'] != 'Debit_AP' && $filter['type'] != 'Debit_MP' && $filter['type'] != 'TXFee' && $filter['type'] != 'Credit_PPS' && $filter['type'] != 'Fee_PPS' && $filter['type'] != 'Donation_PPS')) { |
||
206 | $aFilter[] = "( b.confirmations >= " . $this->config['confirmations'] . " OR ISNULL(b.confirmations) )"; |
||
207 | } |
||
208 | break; |
||
209 | case 'Unconfirmed': |
||
210 | $aFilter[] = "( b.confirmations < " . $this->config['confirmations'] . " AND b.confirmations >= 0 )"; |
||
211 | break; |
||
212 | case 'Orphan': |
||
213 | $aFilter[] = "( b.confirmations = -1 )"; |
||
214 | break; |
||
215 | } |
||
216 | break; |
||
217 | case 'account': |
||
218 | $aFilter[] = "( LOWER(a.username) = LOWER(?) )"; |
||
219 | $this->addParam('s', $value); |
||
220 | break; |
||
221 | case 'address': |
||
222 | $aFilter[] = "( t.coin_address = ? )"; |
||
223 | $this->addParam('s', $value); |
||
224 | break; |
||
225 | } |
||
226 | } |
||
227 | } |
||
228 | if (!empty($aFilter)) { |
||
229 | empty($account_id) ? $sql .= " WHERE " : $sql .= " AND "; |
||
230 | $sql .= implode(' AND ', $aFilter); |
||
231 | } |
||
232 | } |
||
233 | $sql .= " ORDER BY id DESC LIMIT ?,?"; |
||
234 | // Add some other params to query |
||
235 | $this->addParam('i', $start); |
||
236 | $this->addParam('i', $limit); |
||
237 | $stmt = $this->mysqli->prepare($sql); |
||
238 | if ($this->checkStmt($stmt) && call_user_func_array( array($stmt, 'bind_param'), $this->getParam()) && $stmt->execute() && $result = $stmt->get_result()) |
||
239 | return $result->fetch_all(MYSQLI_ASSOC); |
||
240 | return $this->sqlError(); |
||
0 ignored issues
–
show
The return type of
return $this->sqlError(); (boolean ) is incompatible with the return type documented by Transaction::getTransactions 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 ![]() |
|||
241 | } |
||
242 | |||
243 | /** |
||
244 | * Get all different transaction types |
||
245 | * @return mixed array/bool Return types on succes, false on failure |
||
246 | **/ |
||
247 | public function getTypes() { |
||
248 | $stmt = $this->mysqli->prepare("SELECT DISTINCT type FROM $this->table"); |
||
249 | View Code Duplication | if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) { |
|
0 ignored issues
–
show
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. ![]() |
|||
250 | $aData = array('' => ''); |
||
251 | while ($row = $result->fetch_assoc()) { |
||
252 | $aData[$row['type']] = $row['type']; |
||
253 | } |
||
254 | return $aData; |
||
255 | } |
||
256 | return $this->sqlError(); |
||
257 | } |
||
258 | |||
259 | /** |
||
260 | * Get all donation transactions |
||
261 | * Used on donors page |
||
262 | * return data array Donors and amounts |
||
263 | **/ |
||
264 | public function getDonations() { |
||
265 | $this->debug->append("STA " . __METHOD__, 4); |
||
266 | $stmt = $this->mysqli->prepare(" |
||
267 | SELECT |
||
268 | SUM(t.amount) AS donation, |
||
269 | a.username AS username, |
||
270 | a.is_anonymous AS is_anonymous, |
||
271 | ROUND(a.donate_percent, 2) AS donate_percent |
||
272 | FROM $this->table AS t |
||
273 | LEFT JOIN " . $this->user->getTableName() . " AS a |
||
274 | ON t.account_id = a.id |
||
275 | LEFT JOIN " . $this->block->getTableName() . " AS b |
||
276 | ON t.block_id = b.id |
||
277 | WHERE |
||
278 | ( |
||
279 | ( t.type = 'Donation' AND b.confirmations >= " . $this->config['confirmations'] . " ) OR |
||
280 | t.type = 'Donation_PPS' |
||
281 | ) |
||
282 | GROUP BY a.username |
||
283 | ORDER BY donation DESC |
||
284 | "); |
||
285 | if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) |
||
286 | return $result->fetch_all(MYSQLI_ASSOC); |
||
287 | return $this->sqlError(); |
||
288 | } |
||
289 | |||
290 | /** |
||
291 | * Get total balance for all users locked in wallet |
||
292 | * This includes any outstanding unconfirmed transactions! |
||
293 | * @param none |
||
294 | * @return data double Amount locked for users |
||
295 | **/ |
||
296 | public function getLockedBalance() { |
||
297 | $this->debug->append("STA " . __METHOD__, 4); |
||
298 | $stmt = $this->mysqli->prepare(" |
||
299 | SELECT |
||
300 | ( |
||
301 | SUM( IF( ( t.type IN ('Credit','Bonus') AND b.confirmations >= ? ) OR t.type = 'Credit_PPS', t.amount, 0 ) ) - |
||
302 | SUM( IF( t.type IN ('Debit_MP', 'Debit_AP'), t.amount, 0 ) ) - |
||
303 | SUM( IF( ( t.type IN ('Donation','Fee') AND b.confirmations >= ? ) OR ( t.type IN ('Donation_PPS', 'Fee_PPS', 'TXFee') ), t.amount, 0 ) ) |
||
304 | ) AS balance |
||
305 | FROM $this->table AS t |
||
306 | LEFT JOIN " . $this->block->getTableName() . " AS b |
||
307 | ON t.block_id = b.id |
||
308 | WHERE archived = 0"); |
||
309 | View Code Duplication | if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $this->config['confirmations'], $this->config['confirmations']) && $stmt->execute() && $stmt->bind_result($dBalance) && $stmt->fetch()) |
|
0 ignored issues
–
show
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. ![]() |
|||
310 | return $dBalance; |
||
0 ignored issues
–
show
|
|||
311 | return $this->sqlError(); |
||
0 ignored issues
–
show
The return type of
return $this->sqlError(); (boolean ) is incompatible with the return type documented by Transaction::getLockedBalance 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 ![]() |
|||
312 | } |
||
313 | |||
314 | /** |
||
315 | * Get an accounts total balance, ignore archived entries |
||
316 | * @param account_id int Account ID |
||
317 | * @return data float Credit - Debit - Fees - Donation |
||
318 | **/ |
||
319 | public function getBalance($account_id) { |
||
320 | $this->debug->append("STA " . __METHOD__, 4); |
||
321 | $stmt = $this->mysqli->prepare(" |
||
322 | SELECT |
||
323 | IFNULL(( |
||
324 | SUM( IF( ( t.type IN ('Credit','Bonus') AND b.confirmations >= ? ) OR t.type = 'Credit_PPS', t.amount, 0 ) ) - |
||
325 | SUM( IF( t.type IN ('Debit_MP', 'Debit_AP'), t.amount, 0 ) ) - |
||
326 | SUM( IF( ( t.type IN ('Donation','Fee') AND b.confirmations >= ? ) OR ( t.type IN ('Donation_PPS', 'Fee_PPS', 'TXFee') ), t.amount, 0 ) ) |
||
327 | ), 0) AS confirmed, |
||
328 | IFNULL(( |
||
329 | SUM( IF( t.type IN ('Credit','Bonus') AND b.confirmations < ? AND b.confirmations >= 0, t.amount, 0 ) ) - |
||
330 | SUM( IF( t.type IN ('Donation','Fee') AND b.confirmations < ? AND b.confirmations >= 0, t.amount, 0 ) ) |
||
331 | ), 0) AS unconfirmed, |
||
332 | IFNULL(( |
||
333 | SUM( IF( t.type IN ('Credit','Bonus') AND b.confirmations = -1, t.amount, 0) ) - |
||
334 | SUM( IF( t.type IN ('Donation','Fee') AND b.confirmations = -1, t.amount, 0) ) |
||
335 | ), 0) AS orphaned |
||
336 | FROM $this->table AS t |
||
337 | LEFT JOIN " . $this->block->getTableName() . " AS b |
||
338 | ON t.block_id = b.id |
||
339 | WHERE t.account_id = ? |
||
340 | AND archived = 0 |
||
341 | "); |
||
342 | if ($this->checkStmt($stmt) && $stmt->bind_param("iiiii", $this->config['confirmations'], $this->config['confirmations'], $this->config['confirmations'], $this->config['confirmations'], $account_id) && $stmt->execute() && $result = $stmt->get_result()) |
||
343 | return $result->fetch_assoc(); |
||
344 | return $this->sqlError(); |
||
0 ignored issues
–
show
The return type of
return $this->sqlError(); (boolean ) is incompatible with the return type documented by Transaction::getBalance 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 ![]() |
|||
345 | } |
||
346 | |||
347 | /** |
||
348 | * Get our Auto Payout queue |
||
349 | * @param none |
||
350 | * @return data array Account settings and confirmed balances |
||
351 | **/ |
||
352 | public function getAPQueue($limit=250) { |
||
353 | $this->debug->append("STA " . __METHOD__, 4); |
||
354 | $stmt = $this->mysqli->prepare(" |
||
355 | SELECT |
||
356 | a.id, |
||
357 | a.username, |
||
358 | ca.ap_threshold, |
||
359 | ca.coin_address, |
||
360 | IFNULL( |
||
361 | ( |
||
362 | SUM( IF( ( t.type IN ('Credit','Bonus') AND b.confirmations >= " . $this->config['confirmations'] . ") OR t.type = 'Credit_PPS', t.amount, 0 ) ) - |
||
363 | SUM( IF( t.type IN ('Debit_MP', 'Debit_AP'), t.amount, 0 ) ) - |
||
364 | SUM( IF( ( t.type IN ('Donation','Fee') AND b.confirmations >= " . $this->config['confirmations'] . ") OR ( t.type IN ('Donation_PPS', 'Fee_PPS', 'TXFee') ), t.amount, 0 ) ) |
||
365 | ), 0 |
||
366 | ) AS confirmed |
||
367 | FROM $this->table AS t |
||
368 | LEFT JOIN " . $this->block->getTableName() . " AS b |
||
369 | ON t.block_id = b.id |
||
370 | LEFT JOIN " . $this->user->getTableName() . " AS a |
||
371 | ON t.account_id = a.id |
||
372 | LEFT JOIN " . $this->coin_address->getTableName() . " AS ca |
||
0 ignored issues
–
show
The property
coin_address 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;
![]() |
|||
373 | ON ca.account_id = a.id |
||
374 | WHERE t.archived = 0 AND ca.ap_threshold > 0 AND ca.coin_address IS NOT NULL AND ca.coin_address != '' AND ca.currency = ? |
||
375 | GROUP BY t.account_id |
||
376 | HAVING confirmed > ca.ap_threshold AND confirmed > " . $this->config['txfee_auto'] . " |
||
377 | LIMIT ?"); |
||
378 | View Code Duplication | if ($this->checkStmt($stmt) && $stmt->bind_param('si', $this->config['currency'], $limit) && $stmt->execute() && $result = $stmt->get_result()) |
|
0 ignored issues
–
show
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. ![]() |
|||
379 | return $result->fetch_all(MYSQLI_ASSOC); |
||
380 | return $this->sqlError(); |
||
0 ignored issues
–
show
The return type of
return $this->sqlError(); (boolean ) is incompatible with the return type documented by Transaction::getAPQueue 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 ![]() |
|||
381 | } |
||
382 | |||
383 | |||
384 | /** |
||
385 | * Debit a user account |
||
386 | * @param account_id int Account ID |
||
387 | * @param coin_address string Coin Address |
||
388 | * @param amount float Balance to record |
||
389 | * @return int Debit transaction ID or false |
||
390 | **/ |
||
391 | public function createDebitMPRecord($account_id, $coin_address, $amount) { |
||
392 | return $this->createDebitRecord($account_id, $coin_address, $amount, 'Debit_MP'); |
||
393 | } |
||
394 | public function createDebitAPRecord($account_id, $coin_address, $amount) { |
||
395 | return $this->createDebitRecord($account_id, $coin_address, $amount, 'Debit_AP'); |
||
396 | } |
||
397 | private function createDebitRecord($account_id, $coin_address, $amount, $type) { |
||
398 | // Calculate and deduct txfee from amount |
||
399 | $type == 'Debit_MP' ? $txfee = $this->config['txfee_manual'] : $txfee = $this->config['txfee_auto']; |
||
400 | $amount = $amount - $txfee; |
||
401 | // Add Debit record |
||
402 | View Code Duplication | if (!$this->addTransaction($account_id, $amount, $type, NULL, $coin_address, NULL)) { |
|
0 ignored issues
–
show
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. ![]() |
|||
403 | $this->setErrorMessage('Failed to create ' . $type . ' transaction record in database'); |
||
404 | return false; |
||
405 | } |
||
406 | // Fetch the inserted record ID so we can return this at the end |
||
407 | $transaction_id = $this->insert_id; |
||
408 | // Add TXFee record |
||
409 | View Code Duplication | if ($txfee > 0) { |
|
0 ignored issues
–
show
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. ![]() |
|||
410 | if (!$this->addTransaction($account_id, $txfee, 'TXFee', NULL, $coin_address)) { |
||
411 | $this->setErrorMessage('Failed to create TXFee transaction record in database: ' . $this->getError()); |
||
412 | return false; |
||
413 | } |
||
414 | } |
||
415 | // Mark transactions archived |
||
416 | if (!$this->setArchived($account_id, $this->insert_id)) { |
||
417 | $this->setErrorMessage('Failed to mark transactions <= #' . $this->insert_id . ' as archived. ERROR: ' . $this->getError()); |
||
418 | return false; |
||
419 | } |
||
420 | // Recheck the users balance to make sure it is now 0 |
||
421 | if (!$aBalance = $this->getBalance($account_id)) { |
||
422 | $this->setErrorMessage('Failed to fetch balance for account ' . $account_id . '. ERROR: ' . $this->getCronError()); |
||
423 | return false; |
||
424 | } |
||
425 | if ($aBalance['confirmed'] > 0) { |
||
426 | $this->setErrorMessage('User has a remaining balance of ' . $aBalance['confirmed'] . ' after a successful payout!'); |
||
427 | return false; |
||
428 | } |
||
429 | // Notify user via mail |
||
430 | $aMailData['email'] = $this->user->getUserEmailById($account_id); |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$aMailData was never initialized. Although not strictly required by PHP, it is generally a good practice to add $aMailData = 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 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. ![]() |
|||
431 | $aMailData['subject'] = $type . ' Completed'; |
||
432 | $aMailData['amount'] = $amount; |
||
433 | $aMailData['currency'] = $this->config['currency']; |
||
434 | if (!$this->notification->sendNotification($account_id, 'payout', $aMailData)) { |
||
435 | $this->setErrorMessage('Failed to send notification email to users address: ' . $aMailData['email'] . 'ERROR: ' . $this->notification->getCronError()); |
||
0 ignored issues
–
show
The property
notification 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;
![]() |
|||
436 | } |
||
437 | return $transaction_id; |
||
438 | } |
||
439 | |||
440 | /** |
||
441 | * Get all new, unprocessed manual payout requests |
||
442 | * @param none |
||
443 | * @return data Associative array with DB Fields |
||
444 | **/ |
||
445 | public function getMPQueue($limit=250) { |
||
446 | $stmt = $this->mysqli->prepare(" |
||
447 | SELECT |
||
448 | a.id, |
||
449 | a.username, |
||
450 | ca.ap_threshold, |
||
451 | ca.coin_address, |
||
452 | p.id AS payout_id, |
||
453 | IFNULL( |
||
454 | ( |
||
455 | SUM( IF( ( t.type IN ('Credit','Bonus') AND b.confirmations >= " . $this->config['confirmations'] . ") OR t.type = 'Credit_PPS', t.amount, 0 ) ) - |
||
456 | SUM( IF( t.type IN ('Debit_MP', 'Debit_AP'), t.amount, 0 ) ) - |
||
457 | SUM( IF( ( t.type IN ('Donation','Fee') AND b.confirmations >= " . $this->config['confirmations'] . ") OR ( t.type IN ('Donation_PPS', 'Fee_PPS', 'TXFee') ), t.amount, 0 ) ) |
||
458 | ), 0 |
||
459 | ) AS confirmed |
||
460 | FROM " . $this->payout->getTableName() . " AS p |
||
0 ignored issues
–
show
The property
payout 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;
![]() |
|||
461 | JOIN " . $this->user->getTableName() . " AS a |
||
462 | ON p.account_id = a.id |
||
463 | JOIN " . $this->getTableName() . " AS t |
||
464 | ON t.account_id = p.account_id |
||
465 | LEFT JOIN " . $this->block->getTableName() . " AS b |
||
466 | ON t.block_id = b.id |
||
467 | LEFT JOIN " . $this->coin_address->getTableName() . " AS ca |
||
468 | ON ca.account_id = a.id |
||
469 | WHERE p.completed = 0 AND t.archived = 0 AND ca.currency = ? AND ca.coin_address IS NOT NULL AND ca.coin_address != '' |
||
470 | GROUP BY t.account_id |
||
471 | HAVING confirmed > " . $this->config['txfee_manual'] . " |
||
472 | LIMIT ?"); |
||
473 | View Code Duplication | if ($this->checkStmt($stmt) && $stmt->bind_param('si', $this->config['currency'], $limit) && $stmt->execute() && $result = $stmt->get_result()) |
|
0 ignored issues
–
show
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. ![]() |
|||
474 | return $result->fetch_all(MYSQLI_ASSOC); |
||
475 | return $this->sqlError('E0050'); |
||
0 ignored issues
–
show
The return type of
return $this->sqlError('E0050'); (boolean ) is incompatible with the return type documented by Transaction::getMPQueue 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 ![]() |
|||
476 | } |
||
477 | } |
||
478 | |||
479 | $transaction = new Transaction(); |
||
480 | $transaction->setMemcache($memcache); |
||
481 | $transaction->setNotification($notification); |
||
482 | $transaction->setSetting($setting); |
||
483 | $transaction->setDebug($debug); |
||
484 | $transaction->setCoin($coin); |
||
485 | $transaction->setCoinAddress($coin_address); |
||
486 | $transaction->setMysql($mysqli); |
||
487 | $transaction->setConfig($config); |
||
488 | $transaction->setBlock($block); |
||
489 | $transaction->setUser($user); |
||
490 | $transaction->setPayout($oPayout); |
||
491 | $transaction->setErrorCodes($aErrorCodes); |
||
492 |
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: