Fixes + asserts
[mailer.git] / inc / libs / transaction_functions.php
1 <?php
2 /************************************************************************
3  * Mailer v0.2.1-FINAL                                Start: 06/22/2013 *
4  * ===================                          Last change: 06/22/2013 *
5  *                                                                      *
6  * -------------------------------------------------------------------- *
7  * File              : transaction_functions.php                        *
8  * -------------------------------------------------------------------- *
9  * Short description : Functions for ext-transaction                    *
10  * -------------------------------------------------------------------- *
11  * Kurzbeschreibung  : Funktionen fuer ext-transaction                  *
12  * -------------------------------------------------------------------- *
13  * $Revision::                                                        $ *
14  * $Date::                                                            $ *
15  * $Tag:: 0.2.1-FINAL                                                 $ *
16  * $Author::                                                          $ *
17  * -------------------------------------------------------------------- *
18  * Copyright (c) 2003 - 2009 by Roland Haeder                           *
19  * Copyright (c) 2009 - 2013 by Mailer Developer Team                   *
20  * For more information visit: http://mxchange.org                      *
21  *                                                                      *
22  * This program is free software; you can redistribute it and/or modify *
23  * it under the terms of the GNU General Public License as published by *
24  * the Free Software Foundation; either version 2 of the License, or    *
25  * (at your option) any later version.                                  *
26  *                                                                      *
27  * This program is distributed in the hope that it will be useful,      *
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
30  * GNU General Public License for more details.                         *
31  *                                                                      *
32  * You should have received a copy of the GNU General Public License    *
33  * along with this program; if not, write to the Free Software          *
34  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,               *
35  * MA  02110-1301  USA                                                  *
36  ************************************************************************/
37
38 // Some security stuff...
39 if (!defined('__SECURITY')) {
40         die();
41 } // END - if
42
43 // Logs a transaction and "signs" it
44 function logTransaction ($sender, $receiver, $level, $valueAmount, $originalAmount, $transactionSubject) {
45         // Check all conditions
46         assert(((is_null($sender)) || (isValidId($sender))) && (isValidId($receiver)) && ((is_null($level)) || (isValidNumber($level))) && ($valueAmount > 0) && ($originalAmount > 0));
47
48         // Record the transaction for later fee collection
49         sqlQueryEscaped("INSERT INTO
50         `{?_MYSQL_PREFIX?}_transaction_log`
51 (
52         `transaction_sender`,
53         `transaction_receiver`,
54         `transaction_level`,
55         `transaction_value`,
56         `transaction_original`,
57         `transaction_fee_sender`,
58         `transaction_fee_sender_percents`,
59         `transaction_fee_receiver`,
60         `transaction_fee_receiver_percents`,
61         `transaction_subject`
62 ) VALUES (
63         %s,
64         %s,
65         %s,
66         %01.5f,
67         %01.5f,
68         %01.5f,
69         %01.5f,
70         %01.5f,
71         %01.5f,
72         '%s'
73 )",
74                 array(
75                         convertNull($sender),
76                         bigintval($receiver),
77                         convertNull($level),
78                         $valueAmount,
79                         $originalAmount,
80                         calculateSenderTransactionFee($originalAmount),
81                         getConfig('transaction_fee_sender'),
82                         calculateReceiverTransactionFee($valueAmount),
83                         getConfig('transaction_fee_receiver'),
84                         $transactionSubject
85                 ), __FUNCTION__, __LINE__
86         );
87
88         // Should work
89         assert(isValidId(getSqlInsertId()), 'getSqlInsertId() is not valid id number.');
90 }
91
92 // Calculates transaction fee for sender amount
93 function calculateSenderTransactionFee ($amount) {
94         // Calculate it
95         $fee = $amount * getConfig('transaction_fee_sender') / 100;
96
97         // Return fee
98         return $fee;
99 }
100
101 // Calculates transaction fee for receiver amount
102 function calculateReceiverTransactionFee ($amount) {
103         // Calculate it
104         $fee = $amount * getConfig('transaction_fee_receiver') / 100;
105
106         // Return fee
107         return $fee;
108 }
109
110 // Hashes given transaction data
111 function generateHashFromTransactionData (array &$data, $oldHash = '') {
112         // Add CAPTCHA code, if missing
113         if (!isset($data['transaction_captcha'])) {
114                 // Add it
115                 $data['transaction_captcha'] = generateId(
116                         5,
117                         implode(
118                                 ':',
119                                 $data
120                         )
121                 );
122         } // END - if
123
124         // Convert some possible NULL values
125         $data['transaction_sender'] = convertNull($data['transaction_sender']);
126
127         // Generate string to hash
128         $string = implode(':', $data);
129
130         // Hash it then
131         $hash = hashString($string, $oldHash);
132
133         // Return it
134         return $hash;
135 }
136
137 // "Getter" for CAPTCHA code from given transaction id
138 function getCaptchaCodeFromTransactionId ($transactionId) {
139         // Must be valid
140         assert(isValidId($transactionId), 'transactionId=' . $transactionId . ' is not valid id number.');
141
142         // Default is NULL
143         $code = NULL;
144
145         // Search for it
146         $result = sqlQueryEscaped("SELECT
147         `transaction_captcha`
148 FROM
149         `{?_MYSQL_PREFIX?}_transaction_log`
150 WHERE
151         `transaction_id`=%s AND
152         `transaction_level` IS NULL AND
153         `transaction_captcha` IS NOT NULL
154 LIMIT 1",
155                 array(
156                         bigintval($transactionId)
157                 ), __FUNCTION__, __LINE__
158         );
159
160         // Is it there?
161         if (sqlNumRows($result) == 1) {
162                 // Load it
163                 list($code) = sqlFetchRoww($result);
164         } // END - if
165
166         // Free result
167         sqlFreeResult($result);
168
169         // Return it
170         return $code;
171 }
172
173 // Tries to confirm given transactions
174 function doTryConfirmTransactions (array $post) {
175         // Make sure only members can do this
176         assert((isMember()) && (isset($post['ok'])) && (ifPostHasSelection('transaction_id', $post)));
177
178         // Remove submit button
179         unset($post['ok']);
180
181         // Default is not working ;-)
182         $confirmed = FALSE;
183
184         // Init arrays/variables
185         $confirmedIds = array();
186         $failedIds = array();
187         $points = 0;
188
189         // "Walk" through all transaction ids
190         foreach ($post['transaction_id'] as $transactionId => $code) {
191                 // Process only valid ids/CAPTCHA codes
192                 if ((isValidId($transactionId)) && (empty($code))) {
193                         // Empty code found, no CAPTCHA entered
194                         continue;
195                 } elseif ((!isValidId($transactionId)) || (!isValidNumber($code))) {
196                         // Better set it as "invalid" explicitly and abort here
197                         $confirmed = FALSE;
198                         break;
199                 }
200
201                 // Init data array
202                 $data = array();
203
204                 // Try to load more transaction data
205                 $result = sqlQueryEscaped("SELECT
206         `transaction_id`,
207         `transaction_hash`,
208         `transaction_sender`,
209         `transaction_receiver`,
210         `transaction_fee_sender`,
211         `transaction_fee_receiver`,
212         `transaction_original`,
213         `transaction_subject`,
214         `transaction_timestamp`
215 FROM
216         `{?_MYSQL_PREFIX?}_transaction_log`
217 WHERE
218         `transaction_id`=%s AND
219         `transaction_hash` != 'INVALID' AND
220         `transaction_sender` != %s AND
221         `transaction_sender` IS NOT NULL AND
222         `transaction_receiver` != %s AND
223         `transaction_receiver` IS NOT NULL AND
224         `transaction_confirmed`='N' AND
225         `transaction_level` IS NULL AND
226         `transaction_captcha` IS NOT NULL
227 LIMIT 1",
228                         array(
229                                 bigintval($transactionId),
230                                 getCurrentUserId(),
231                                 getCurrentUserId()
232                         ), __FUNCTION__, __LINE__
233                 );
234
235                 // Is there one entry?
236                 if (sqlNumRows($result) == 1) {
237                         // Then load it
238                         $data = sqlFetchArray($result);
239
240                         /*
241                          * Save hash for later usage and remove it, so that the hasher
242                          * function will calculate the same hash if same CAPTCHA code
243                          * has been entered.
244                          */
245                         $oldHash = $data['transaction_hash'];
246                         unset($data['transaction_hash']);
247
248                         // Set captcha code from POST data
249                         $data['transaction_captcha'] = bigintval($code);
250
251                         // Generate hash again
252                         $hash = generateHashFromTransactionData($data, $oldHash);
253
254                         // Is it the same?
255                         $confirmed = ($hash == $oldHash);
256                         if ($confirmed === TRUE) {
257                                 // Then mark it as confirmed and count all points
258                                 array_push($confirmedIds, $transactionId);
259                                 $points += $data['transaction_fee_sender'] + $data['transaction_fee_receiver'];
260                         } else {
261                                 // Failed confirmation
262                                 array_push($failedIds, $transactionId);
263                         }
264                 } // END - if
265
266                 // Free result
267                 sqlFreeResult($result);
268
269                 // If it is not found, abort here
270                 if (!isFilledArray($data)) {
271                         // Is not valid, better explicitly set it here and abort
272                         $confirmed = FALSE;
273                         break;
274                 } // END - if
275         } // END - foreach
276
277         // Were all transaction ids valid?
278         if ($confirmed === TRUE) {
279                 // Update all confirmed transactions
280                 sqlQueryEscaped("UPDATE
281         `{?_MYSQL_PREFIX?}_transaction_log`
282 SET
283         `transaction_confirmed`='Y'
284 WHERE
285         `transaction_id` IN (" . implode(',', $confirmedIds) . ") AND
286         `transaction_hash` != 'INVALID' AND
287         `transaction_sender` != %s AND
288         `transaction_sender` IS NOT NULL AND
289         `transaction_receiver` != %s AND
290         `transaction_receiver` IS NOT NULL AND
291         `transaction_confirmed`='N'
292 LIMIT %s",
293                         array(
294                                 getCurrentUserId(),
295                                 getCurrentUserId(),
296                                 count($confirmedIds)
297                         ), __FUNCTION__, __LINE__
298                 );
299
300                 // Check if all has been updated
301                 $confirmed = (sqlAffectedRows() == count($confirmedIds));
302
303                 // Has all confirmed?
304                 if ($confirmed === TRUE) {
305                         // Allowed fields
306                         $allowed = array(
307                                 'transaction_fees',
308                                 'transaction_confirmed',
309                                 'transaction_confirmed_yearly',
310                                 'transaction_count'
311                         );
312
313                         // Add them user's "pot"
314                         $updated = doUpdateMemberProfileData(array(
315                                 'transaction_fees'             => getUserData('transaction_fees')             + $points,
316                                 'transaction_confirmed'        => getUserData('transaction_confirmed')        + count($confirmedIds),
317                                 'transaction_confirmed_yearly' => getUserData('transaction_confirmed_yearly') + count($confirmedIds),
318                                 'transaction_count'            => getUserData('transaction_count')            + (count($confirmedIds) * getConfig('transaction_count_captcha_confirm'))
319                         ), $allowed, '', FALSE);
320
321                         // Should always work
322                         assert($updated === TRUE, 'Nothing has been updated which is not expected.');
323                 } // END - if
324         } // END - if
325
326         // Are there some failed transactions?
327         if (count($failedIds) > 0) {
328                 // Then update all
329                 sqlQueryEscaped("UPDATE
330         `{?_MYSQL_PREFIX?}_transaction_log`
331 SET
332         `transaction_captcha_failed`='Y'
333 WHERE
334         `transaction_id` IN (" . implode(',', $failedIds) . ") AND
335         `transaction_hash` != 'INVALID' AND
336         `transaction_sender` != %s AND
337         `transaction_sender` IS NOT NULL AND
338         `transaction_receiver` != %s AND
339         `transaction_receiver` IS NOT NULL AND
340         `transaction_confirmed`='N'
341 LIMIT %s",
342                         array(
343                                 getCurrentUserId(),
344                                 getCurrentUserId(),
345                                 count($failedIds)
346                         ), __FUNCTION__, __LINE__
347                 );
348
349                 // Should always work
350                 assert(sqlAffectedRows() == count($failedIds), 'sqlAffectedRows()=' . sqlAffectedRows() . ',failedIds()=' . count($failedIds));
351         } // END - if
352
353         // Return status
354         return $confirmed;
355 }
356
357 // Checks whether the given user has a fee exempt
358 function ifUserHasTransactionFeeExempt ($username) {
359         // Accept only valid ids
360         assert(isValidId($username), 'username=' . $username . ' which is not a valid id number.');
361
362         // Is there "cache"?
363         if (!isset($GLOBALS[__FUNCTION__][$username])) {
364                 // Default is the user has no excempt
365                 $GLOBALS[__FUNCTION__][$username] = FALSE;
366
367                 // "Determine" it
368                 $GLOBALS[__FUNCTION__][$username] = (getTotalPoints($username) < getConfig('transaction_fee_exempt_amount'));
369         } // END - if
370
371         // Return cache
372         return $GLOBALS[__FUNCTION__][$username];
373 }
374
375 // [EOF]
376 ?>