Completed
Push — master ( 625e32...22cdbd )
by Michael
02:37
created

ipnppd.php (2 issues)

Upgrade to new PHP Analysis Engine

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

1
<?php
2
/************************************************************************/
3
/* Donations - Paypal financial management module for Xoops 2           */
4
/* Copyright (c) 2016 XOOPS Project                                     */
5
/* http://dev.xoops.org/modules/xfmod/project/?group_id=1060            */
6
/* 
7
/************************************************************************/
8
/*                                                                      */
9
/* Based on NukeTreasury for PHP-Nuke - by Dave Lawrence AKA Thrash     */
10
/* NukeTreasury - Financial management for PHP-Nuke                     */
11
/* Copyright (c) 2004 by Dave Lawrence AKA Thrash                       */
12
/*                       [email protected]                         */
13
/*                       [email protected]                          */
14
/*                                                                      */
15
/************************************************************************/
16
/*                                                                      */
17
/* This program is free software; you can redistribute it and/or modify */
18
/* it under the terms of the GNU General Public License as published by */
19
/* the Free Software Foundation; either version 2 of the License.       */
20
/*                                                                      */
21
/* This program is distributed in the hope that it will be useful, but  */
22
/* WITHOUT ANY WARRANTY; without even the implied warranty of           */
23
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU     */
24
/* General Public License for more details.                             */
25
/*                                                                      */
26
/* You should have received a copy of the GNU General Public License    */
27
/* along with this program; if not, write to the Free Software          */
28
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  */
29
/* USA                                                                  */
30
/************************************************************************/
31
32
//$xoopsOption['nocommon'] = 1;
33
include __DIR__ . '/header.php';
34
include_once 'include/functions.php';
35
include_once XOOPS_ROOT_PATH . '/class/xoopsformloader.php';
36
37
$tr_config  = configInfo();
38
$paypal_url = explode('|', $tr_config['paypal_url']);
39
$paypal_url = $paypal_url[0];
40
//determine the currency
41
$PP_CURR_CODE = explode('|', $tr_config['pp_curr_code']); // [USD,GBP,JPY,CAD,EUR]
42
$PP_CURR_CODE = $PP_CURR_CODE[0];
43
$currencySign    = defineCurrency($PP_CURR_CODE);
44
45
$pp_varlist = simple_query($xoopsDB->prefix('donations_transactions'), '', '', array('id'));
46
47
define('_ERR', 1);
48
define('_INF', 2);
49
$ERR    = 0;
50
$log    = '';
51
$loglvl = $tr_config['ipn_dbg_lvl'];
52
53
// creates a log file in the XOOPS uploads directory
54
$lpFile = XOOPS_UPLOAD_PATH . '/xdonations_ipn.log';
55
if ( false!=($lp = fopen($lpFile, 'w+'))) {
56
    dprt(_MD_DON_LOGFILE_CREATED, _INF);
57
} else {
58
    dprt(_MD_DON_LOGFILE_NOT_CREATED, _ERR);
59
}
60
dprt(date('r'), _INF);
61
$dbg = (isset($_GET['dbg']) && $_GET['dbg']) ? true : false;
62
63
if ($dbg) {
64
    dprt(_MD_DON_DEBUGACTIVE, _INF);
65
    echo _MD_DON_DEBUGHEADER;
66
    $pp_varlist['receiver_email'] = $tr_config['receiver_email'];
67
}
68
69
// read the post from PayPal system and add 'cmd'
70
$req = 'cmd=_notify-validate';
71
72
foreach ($_POST as $key => $value) {
73
    $value = urlencode(stripslashes($value));
74
    $req .= "&$key=$value";
75
}
76
77
// post back to PayPal system to validate
78
dprt(_MD_DON_OPENCONN, _INF);
79
$fp = fsockopen($paypal_url, 80, $errno, $errstr, 30);
80
81
if (!$fp) { // HTTP ERROR
82
    //TODO: use CURL if fsockopen fails
83
    dprt("<style=\"color: #00CC00;\">" . _MD_DON_CONNFAIL . '</span>', _ERR);
84
    die(sprintf(_MD_DON_POSTBACK_FAIL, $errno, $errstr));
85
} else {
86
    dprt(_MD_DON_POSTBACK_OK, _INF);
87
    $header = "POST /cgi-bin/webscr HTTP/1.0\r\n";
88
    $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
89
    $header .= 'Content-Length: ' . strlen($req) . "\r\n\r\n";
90
}
91
92
// assign posted variables to local variables
93
$pp_varname = array_values(array_intersect(array_keys($pp_varlist), array_keys($_POST)));
94
for ($i = 0, $iMax = count($pp_varname); $i < $iMax; ++$i) {
95
    $pp_varlist[$pp_varname[$i]] = $_POST[$pp_varname[$i]];
96
}
97
98
if ('' == $pp_varlist['payment_date']) { //set blank date to proper format
99
    $pp_varlist['payment_date'] = '0000-00-00 00:00:00';
100
}
101
102
$writeOk = fwrite($fp, $header . $req);
103
if (!$writeOk) { // HTTP ERROR
104
    dprt("<style=\"font-weight: bold; color: #00CC00;\">" . _MD_DON_WRITEFAIL . '</span>', _ERR);
105
    die(sprintf(_MD_DON_ERR_FAILED_WRITE, $errno, $errstr));
106
} else {
107
    dprt(_MD_DON_WRITEOK, _INF);
108
}
109
110
// Perform PayPal email account verification
111
if (!$dbg && (strcasecmp($pp_varlist['business'], $tr_config['receiver_email']) != 0)) {
112
    dprt(sprintf(_MD_DON_BUSINVALID, $pp_varlist['business']), _ERR);
113
    dprt(sprintf(_MD_DON_RCVINVALID, $pp_varlist['receiver_email']), _ERR);
114
    $ERR = 1;
115
}
116
117
$insertSQL = '';
118
// Look for duplicate txn_id's
119
if ($pp_varlist['txn_id']) {
120
    $sql        = 'SELECT COUNT(*) FROM ' . $xoopsDB->prefix('donations_transactions') . " WHERE txn_id = '" . addslashes($pp_varlist['txn_id']) . "'";
121
    $Recordset1 = $xoopsDB->query($sql);
122
    list($NumDups) = $xoopsDB->fetchRow($Recordset1);
123
}
124
if ($pp_varlist['parent_txn_id']) {
125
    $parent_sql            = 'SELECT * FROM ' . $xoopsDB->prefix('donations_transactions') . " WHERE txn_id = '" . addslashes($pp_varlist['parent_txn_id']) . "'";
126
    $parent_Recordset1     = $xoopsDB->query($parent_sql);
127
    $parent_row_Recordset1 = $xoopsDB->fetchArray($parent_Recordset1);
128
    $parent_NumDups        = $xoopsDB->getRowsNum($parent_Recordset1);
129
}
130
131
while (!$dbg && !$ERR && !feof($fp)) {
132
    $res = fgets($fp, 1024);
133
    if (strcmp($res, 'VERIFIED') == 0) {
134
        // Ok - PayPal has told us we have a valid IPN here
135
        dprt(_MD_DON_VERIFIED, _INF);
136
137
        // Check for a reversal for a refund
138
        if (strcmp($pp_varlist['payment_status'], 'Refunded') == 0 || strcmp($pp_varlist['txn_type'], 'Reversal') == 0) {
139
            // Verify the reversal
140
            dprt(_MD_DON_REFUND, _INF);
141
            if (($parent_NumDups == 0) || strcmp($parent_row_Recordset1['payment_status'], 'Completed') || (strcmp($parent_row_Recordset1['txn_type'], 'web_accept') != 0 && strcmp($parent_row_Recordset1['txn_type'], 'send_money') != 0)) {
142
                // This is an error.  A reversal implies a pre-existing completed transaction
143
                dprt(_MD_DON_TRANSMISSING, _ERR);
144
                foreach ($_POST as $key => $val) {
145
                    dprt("$key => $val", _ERR);
146
                }
147
                break;
148
            }
149
            if (1 != $parent_NumDups) {
150
                dprt(_MD_DON_MULTITXNS, _ERR);
151
                foreach ($_POST as $key => $val) {
152
                    dprt("$key => $val", _ERR);
153
                }
154
                break;
155
            }
156
157
            /* TODO: Need to add info to database.  If user donates, then cancels a subsequent
158
             * donation then they are removed from group - need a counter to see how many times a
159
             * user has donated and only remove from group if 'everything' donated has been reversed.
160
             */
161
162
            // remove xoopsUsers (not anon) from group selected by Admin in config
163
            if (!empty($pp_varlist['custom'])) {
164
                $member_handler = xoops_getHandler('member');
165
                $edituser       =& $member_handler->getUser($pp_varlist['custom']);
166
167
                // remove the user from the specified group
168
                if ($tr_config['assign_group']) {  // admin has selected a group in admin
169
                    $group_handler = xoops_getHandler('group');
170
                    $validGroup    = $group_handler->get((int)$tr_config['assign_group']); // make sure this is a valid group id
171
                    if ($validGroup) {
172
                        $thisUserGroups = $member_handler->getGroupsByUser((int)$edituser->getVar('uid'));
173
                        if (!in_array($validGroup->getVar('groupid'), $thisUserGroups)) {
174
175
                            // now find out if user is in the group
176
                            $isMember = $member_handler->getGroupsByUser($edituser->getVar('uid'));
177
                            if ($isMember) {
178
                                $success = $member_handler->removeUserFromGroup($tr_config['assign_group'], $edituser->getVar('uid'));
179 View Code Duplication
                                if ($success) {
180
                                    dprt('User ' . $edituser->getVar('uname') . ' was removed from the ' . $validGroup->getVar('name') . ' group', _INF);
181
                                } else {
182
                                    dprt('User ' . $edituser->getVar('uname') . ' could not be removed from the ' . $validGroup->getVar('name') . ' group', _ERR);
183
                                }
184
                            }
185
                        } else {
186
                            dprt($edituser->getVar('uname') . ' was not in the ' . $validGroup->getVar('name') . ' group', _INF);
187
                        }
188
                    } else {
189
                        dprt('Group isn\'t valid - change Admin configs option<br />', _ERR);
190
                    }
191
                }
192
                /*
193
                 * TODO: Need to add a db table variable to 'demote' the user's rank back to where
194
                 * it was prior to the reversal
195
                 */
196
            }
197
            $pp_varlist['payment_date'] = strftime('%Y-%m-%d %H:%M:%S', strtotime($pp_varlist['payment_date']));
198
            $field_values               = $field_names = '';
199 View Code Duplication
            for ($i = 0, $iMax = count($pp_varname); $i < $iMax; ++$i) {
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.

Loading history...
200
                if (0 != $i) {
201
                    $field_names .= ',';
202
                    $field_values .= ',';
203
                }
204
                $field_names .= '`' . $pp_varname[$i] . '`';
205
                $field_values .= "'" . $pp_varlist[$pp_varname[$i]] . "'";
206
            }
207
            $insertSQL = 'INSERT INTO ' . $xoopsDB->prefix('donations_transactions') . " ($field_names) VALUES ($field_values)";
208
209
            // We're cleared to add this record
210
            dprt($insertSQL, _INF);
211
            $Result1 = $xoopsDB->queryF($insertSQL);
212
            dprt('SQL result = ' . $Result1, _INF);
213
214
            break;
215
            // Look for a normal payment
216
        } elseif ((strcmp($pp_varlist['payment_status'], 'Completed') == 0) && ((strcmp($pp_varlist['txn_type'], 'web_accept') == 0) || (strcmp($pp_varlist['txn_type'], 'send_money') == 0))) {
217
            dprt(_MD_DON_NORMAL_TXN, _INF);
218
            if ($lp) {
219
                fwrite($lp, $pp_varlist['payer_email'] . ' ' . $pp_varlist['payment_status'] . ' ' . $pp_varlist['payment_date'] . "\n");
220
            }
221
222
            if ($NumDups != 0) { // Check for a duplicate txn_id
223
                dprt(_MD_DON_DUPLICATETXN, _ERR);
224
                foreach ($_POST as $key => $val) {
225
                    dprt("$key => $val", _ERR);
226
                }
227
                break;
228
            }
229
230
            $pp_varlist['payment_date'] = strftime('%Y-%m-%d %H:%M:%S', strtotime($pp_varlist['payment_date']));
231
            $field_values               = $field_names = '';
232 View Code Duplication
            for ($i = 0, $iMax = count($pp_varname); $i < $iMax; ++$i) {
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.

Loading history...
233
                if ($i != 0) {
234
                    $field_names .= ',';
235
                    $field_values .= ',';
236
                }
237
                $field_names .= '`' . $pp_varname[$i] . '`';
238
                $field_values .= "'" . $pp_varlist[$pp_varname[$i]] . "'";
239
            }
240
            $insertSQL = 'INSERT INTO ' . $xoopsDB->prefix('donations_transactions') . " ($field_names) VALUES ($field_values)";
241
242
            // We're cleared to add this record
243
            dprt($insertSQL, _INF);
244
            $Result1 = $xoopsDB->queryF($insertSQL);
245
            dprt('SQL result = ' . $Result1, _INF);
246
247
            // add xoopsUsers (not anon) to group if selected by Admin in config
248
            if (!empty($pp_varlist['custom']) && (($pp_varlist['option_selection1'] === 'Yes') || ($tr_config['don_forceadd'] == '1'))) {
249
                $member_handler = xoops_getHandler('member');
250
                $edituser       =& $member_handler->getUser($pp_varlist['custom']);
251
252
                // add the user to specified group
253
                if ($tr_config['assign_group']) {  // config option set to add users to a group
254
                    $group_handler = xoops_getHandler('group');
255
                    $validGroup    = $group_handler->get((int)$tr_config['assign_group']); // make sure this is a valid group id
256
                    if ($validGroup) {
257
                        $thisUserGroups = $member_handler->getGroupsByUser((int)$edituser->getVar('uid'));
258
                        if (!in_array($validGroup->getVar('groupid'), $thisUserGroups)) {
259
                            $success = $member_handler->addUserToGroup($validGroup->getVar('groupid'), $edituser->getVar('uid'));
260 View Code Duplication
                            if ($success) {
261
                                dprt('User ' . $edituser->getVar('uname') . ' was added to the ' . $validGroup->getVar('name') . ' group', _INF);
262
                            } else {
263
                                dprt('User ' . $edituser->getVar('uname') . ' could not be addded to the ' . $validGroup->getVar('name') . ' group', _ERR);
264
                            }
265
                        } else {
266
                            dprt($edituser->getVar('uname') . ' is already in the ' . $validGroup->getVar('name') . ' group', _INF);
267
                        }
268
                    } else {
269
                        dprt('Group isn\'t valid - change Admin configs option<br />', _ERR);
270
                    }
271
                }
272
273
                // add the user to a specific rank
274
                if ($tr_config['assign_rank']) {  // config option set to add users to a rank
275
                    $urank = $edituser->rank();
276
                    if (0 != $urank['id']) {
277
                        $result = $xoopsDB->query('SELECT COUNT(*) FROM ' . $xoopsDB->prefix('ranks') . " WHERE rank_id='" . $urank['id'] . "' AND rank_special=0");
278
                        list($rank_check) = $xoopsDB->fetchRow($result);
279
                        $xoopsDB->freeRecordSet($result);
280
                    } else {
281
                        $rank_check = 1;
282
                    }
283
                    if ($rank_check > 0) {
284
                        // set user's new rank
285
                        $edituser->setVar('rank', $tr_config['assign_rank']);
286
                        $member_handler->insertUser($edituser);
287
                    }
288
                }
289
            }
290
            break;
291
        } else { // We're not interested in this transaction, so we're done
292
            dprt(_MD_DON_NOTINTERESTED, _ERR);
293
            foreach ($_POST as $key => $val) {
294
                dprt("$key => $val", _ERR);
295
            }
296
            dprt('pp_varlist:', _ERR);
297
            foreach ($pp_varlist as $key => $val) {
298
                dprt("$key => $val", _ERR);
299
            }
300
            dprt('strcmp payment_status: ' . strcmp($pp_varlist['payment_status'], 'Completed'), _ERR);
301
            dprt('strcmp txn_type: ' . strcmp($pp_varlist['txn_type'], 'web_accept'), _ERR);
302
            dprt('strcmp txn_type: ' . strcmp($pp_varlist['txn_type'], 'send_money'), _ERR);
303
            break;
304
        }
305
    } elseif (strcmp($res, 'INVALID') == 0) {
306
        // log for manual investigation
307
        dprt(_MD_DON_INVALIDIPN, _ERR);
308
        foreach ($_POST as $key => $val) {
309
            dprt("$key => $val", _ERR);
310
        }
311
        break;
312
    } else {
313
        dprt(_MD_DON_ERR_UNKNOWN_IPN_STAT, _ERR);
314
    }
315
}
316
317
if ($dbg) {
318
    $sql = 'SELECT * FROM ' . $xoopsDB->prefix('donations_transactions') . ' LIMIT 10';
319
    dprt(_MD_DON_EXECUTING_QUERY, _INF);
320
    $Result1 = $xoopsDB->query($sql);
321
    if ($Result1) {
322
        dprt("<span style=\"font-weight: bold; color: #00CC00;\">" . _MD_DON_DEBUGPASS . '</span>', _INF);
323
    } else {
324
        dprt("<span style=\"font-weight: bold; color: #CC0000;\">" . _MD_DON_DEBUGFAIL . '</span>', _ERR);
325
    }
326
    dprt(sprintf(_MD_DON_RCVEMAIL, $tr_config['receiver_email']), _INF);
327
}
328
329
if ($log) {
330
    dprt('<br />' . _MD_DON_LOGBEGIN . "<br />\n", _INF);
331
    // Insert the log entry
332
    $currentDate = strftime('%Y-%m-%d %H:%M:%S', time());
333
    $paymentDate = isset($_POST['payment_date']) ? strftime('%Y-%m-%d %H:%M:%S', strtotime($_POST['payment_date'])) : $currentDate;
334
    $sql         = 'INSERT INTO ' . $xoopsDB->prefix('donations_translog') . " VALUES (NULL,'{$currentDate}', '{$paymentDate}','" . addslashes($log) . "')";
335
    $Result1     = $xoopsDB->queryF($sql);
336
337
    // Clear out old log entries
338
    $sql     = 'SELECT COUNT(*) FROM ' . $xoopsDB->prefix('donations_translog');
339
    $Result1 = $xoopsDB->query($sql);
340
    list($countLogs) = $xoopsDB->fetchRow($Result1);
341
    if ($countLogs == $tr_config['ipn_log_entries']) {
342
        $sql     = 'DELETE FROM ' . $xoopsDB->prefix('donations_translog');
343
        $Result1 = $xoopsDB->queryF($sql);
344
        if (false === $Result1) {
345
            dprt(_MD_DON_ERR_TXN_NOCLEAR, _ERR);
346
        } else {
347
            dprt(_MD_DON_ERR_TXN_CLEAR, _INF);
348
        }
349
    }
350
}
351
352
fclose($fp);
353
if ($lp) {
354
    fwrite($lp, _MD_DON_EXITING . "\n");
355
    fclose($lp);
356
}
357
358
if ($dbg) {
359
    echo '<hr />';
360
    echo _MD_DON_IFNOERROR . "<br />\n";
361
    echo "<a href='javascript:window.close();'>Close Window</a>";
362
}
363
364
/**
365
 *
366
 * Debug Message Store/Display
367
 * @param string $str  string to store/display
368
 * @param int    $clvl error reporting level (1 = error, 2= info)
369
 */
370
function dprt($str, $clvl)
371
{
372
    global $dbg, $lp, $log, $loglvl;
373
374
    if (isset($dbg) && $dbg) {
375
        echo $str . '<br />';
376
    }
377
378
    if (isset($loglvl) && ($clvl <= $loglvl)) {
379
        $log .= $str . "\n";
380
        if (isset($lp) && $lp) {
381
            fwrite($lp, strip_tags($str) . "\r\n");
382
        }
383
    }
384
}
385