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 | require_once __DIR__ . '/header.php'; |
||
34 | require_once __DIR__ . '/class/Utility.php'; |
||
35 | require_once XOOPS_ROOT_PATH . '/class/xoopsformloader.php'; |
||
36 | |||
37 | $tr_config = $utility::getConfigInfo(); |
||
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 = $utility::defineCurrency($PP_CURR_CODE); |
||
44 | |||
45 | $pp_varlist = $utility::runSimpleQuery($xoopsDB->prefix('donations_transactions'), '', '', ['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, 'wb+'))) { |
||
56 | dprt(_MD_XDONATION_LOGFILE_CREATED, _INF); |
||
57 | } else { |
||
58 | dprt(_MD_XDONATION_LOGFILE_NOT_CREATED, _ERR); |
||
59 | } |
||
60 | dprt(date('r'), _INF); |
||
61 | $dbg = (isset($_GET['dbg']) && $_GET['dbg']); |
||
62 | |||
63 | if ($dbg) { |
||
64 | dprt(_MD_XDONATION_DEBUGACTIVE, _INF); |
||
65 | echo _MD_XDONATION_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_XDONATION_OPENCONN, _INF); |
||
79 | $fp = fsockopen($paypal_url, 80, $errno, $errstr, 30); |
||
80 | |||
81 | if (!$fp) { // HTTP ERROR |
||
0 ignored issues
–
show
introduced
by
![]() |
|||
82 | //TODO: use CURL if fsockopen fails |
||
83 | dprt('<style="color: #00CC00;">' . _MD_XDONATION_CONNFAIL . '</span>', _ERR); |
||
84 | die(sprintf(_MD_XDONATION_POSTBACK_FAIL, $errno, $errstr)); |
||
85 | } else { |
||
86 | dprt(_MD_XDONATION_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_XDONATION_WRITEFAIL . '</span>', _ERR); |
||
105 | die(sprintf(_MD_XDONATION_ERR_FAILED_WRITE, $errno, $errstr)); |
||
106 | } else { |
||
107 | dprt(_MD_XDONATION_WRITEOK, _INF); |
||
108 | } |
||
109 | |||
110 | // Perform PayPal email account verification |
||
111 | if (!$dbg && (0 != strcasecmp($pp_varlist['business'], $tr_config['receiver_email']))) { |
||
112 | dprt(sprintf(_MD_XDONATION_BUSINVALID, $pp_varlist['business']), _ERR); |
||
113 | dprt(sprintf(_MD_XDONATION_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 (0 == strcmp($res, 'VERIFIED')) { |
||
134 | // Ok - PayPal has told us we have a valid IPN here |
||
135 | dprt(_MD_XDONATION_VERIFIED, _INF); |
||
136 | |||
137 | // Check for a reversal for a refund |
||
138 | if (0 == strcmp($pp_varlist['payment_status'], 'Refunded') |
||
139 | || 0 == strcmp($pp_varlist['txn_type'], 'Reversal')) { |
||
140 | // Verify the reversal |
||
141 | dprt(_MD_XDONATION_REFUND, _INF); |
||
142 | if ((0 == $parent_NumDups) || strcmp($parent_row_Recordset1['payment_status'], 'Completed') |
||
143 | || (0 != strcmp($parent_row_Recordset1['txn_type'], 'web_accept') |
||
144 | && 0 != strcmp($parent_row_Recordset1['txn_type'], 'send_money'))) { |
||
145 | // This is an error. A reversal implies a pre-existing completed transaction |
||
146 | dprt(_MD_XDONATION_TRANSMISSING, _ERR); |
||
147 | foreach ($_POST as $key => $val) { |
||
148 | dprt("$key => $val", _ERR); |
||
149 | } |
||
150 | break; |
||
151 | } |
||
152 | if (1 != $parent_NumDups) { |
||
153 | dprt(_MD_XDONATION_MULTITXNS, _ERR); |
||
154 | foreach ($_POST as $key => $val) { |
||
155 | dprt("$key => $val", _ERR); |
||
156 | } |
||
157 | break; |
||
158 | } |
||
159 | |||
160 | /* TODO: Need to add info to database. If user donates, then cancels a subsequent |
||
161 | * donation then they are removed from group - need a counter to see how many times a |
||
162 | * user has donated and only remove from group if 'everything' donated has been reversed. |
||
163 | */ |
||
164 | |||
165 | // remove xoopsUsers (not anon) from group selected by Admin in config |
||
166 | if (!empty($pp_varlist['custom'])) { |
||
167 | $memberHandler = xoops_getHandler('member'); |
||
168 | $edituser = $memberHandler->getUser($pp_varlist['custom']); |
||
169 | |||
170 | // remove the user from the specified group |
||
171 | if ($tr_config['assign_group']) { // admin has selected a group in admin |
||
172 | $groupHandler = xoops_getHandler('group'); |
||
173 | $validGroup = $groupHandler->get((int)$tr_config['assign_group']); // make sure this is a valid group id |
||
174 | if ($validGroup) { |
||
175 | $thisUserGroups = $memberHandler->getGroupsByUser((int)$edituser->getVar('uid')); |
||
176 | if (!in_array($validGroup->getVar('groupid'), $thisUserGroups)) { |
||
177 | |||
178 | // now find out if user is in the group |
||
179 | $isMember = $memberHandler->getGroupsByUser($edituser->getVar('uid')); |
||
180 | if ($isMember) { |
||
181 | $success = $memberHandler->removeUserFromGroup($tr_config['assign_group'], $edituser->getVar('uid')); |
||
182 | if ($success) { |
||
183 | dprt('User ' . $edituser->getVar('uname') . ' was removed from the ' . $validGroup->getVar('name') . ' group', _INF); |
||
184 | } else { |
||
185 | dprt('User ' . $edituser->getVar('uname') . ' could not be removed from the ' . $validGroup->getVar('name') . ' group', _ERR); |
||
186 | } |
||
187 | } |
||
188 | } else { |
||
189 | dprt($edituser->getVar('uname') . ' was not in the ' . $validGroup->getVar('name') . ' group', _INF); |
||
190 | } |
||
191 | } else { |
||
192 | dprt('Group isn\'t valid - change Admin configs option<br>', _ERR); |
||
193 | } |
||
194 | } |
||
195 | /* |
||
196 | * TODO: Need to add a db table variable to 'demote' the user's rank back to where |
||
197 | * it was prior to the reversal |
||
198 | */ |
||
199 | } |
||
200 | $pp_varlist['payment_date'] = strftime('%Y-%m-%d %H:%M:%S', strtotime($pp_varlist['payment_date'])); |
||
201 | $field_values = $field_names = ''; |
||
202 | for ($i = 0, $iMax = count($pp_varname); $i < $iMax; ++$i) { |
||
203 | if (0 != $i) { |
||
204 | $field_names .= ','; |
||
205 | $field_values .= ','; |
||
206 | } |
||
207 | $field_names .= '`' . $pp_varname[$i] . '`'; |
||
208 | $field_values .= "'" . $pp_varlist[$pp_varname[$i]] . "'"; |
||
209 | } |
||
210 | $insertSQL = 'INSERT INTO ' . $xoopsDB->prefix('donations_transactions') . " ($field_names) VALUES ($field_values)"; |
||
211 | |||
212 | // We're cleared to add this record |
||
213 | dprt($insertSQL, _INF); |
||
214 | $Result1 = $xoopsDB->queryF($insertSQL); |
||
215 | dprt('SQL result = ' . $Result1, _INF); |
||
216 | |||
217 | break; |
||
218 | // Look for a normal payment |
||
219 | } elseif ((0 == strcmp($pp_varlist['payment_status'], 'Completed')) |
||
220 | && ((0 == strcmp($pp_varlist['txn_type'], 'web_accept')) |
||
221 | || (0 == strcmp($pp_varlist['txn_type'], 'send_money')))) { |
||
222 | dprt(_MD_XDONATION_NORMAL_TXN, _INF); |
||
223 | if ($lp) { |
||
224 | fwrite($lp, $pp_varlist['payer_email'] . ' ' . $pp_varlist['payment_status'] . ' ' . $pp_varlist['payment_date'] . "\n"); |
||
225 | } |
||
226 | |||
227 | if (0 != $NumDups) { // Check for a duplicate txn_id |
||
228 | dprt(_MD_XDONATION_DUPLICATETXN, _ERR); |
||
229 | foreach ($_POST as $key => $val) { |
||
230 | dprt("$key => $val", _ERR); |
||
231 | } |
||
232 | break; |
||
233 | } |
||
234 | |||
235 | $pp_varlist['payment_date'] = strftime('%Y-%m-%d %H:%M:%S', strtotime($pp_varlist['payment_date'])); |
||
236 | $field_values = $field_names = ''; |
||
237 | for ($i = 0, $iMax = count($pp_varname); $i < $iMax; ++$i) { |
||
238 | if (0 != $i) { |
||
239 | $field_names .= ','; |
||
240 | $field_values .= ','; |
||
241 | } |
||
242 | $field_names .= '`' . $pp_varname[$i] . '`'; |
||
243 | $field_values .= "'" . $pp_varlist[$pp_varname[$i]] . "'"; |
||
244 | } |
||
245 | $insertSQL = 'INSERT INTO ' . $xoopsDB->prefix('donations_transactions') . " ($field_names) VALUES ($field_values)"; |
||
246 | |||
247 | // We're cleared to add this record |
||
248 | dprt($insertSQL, _INF); |
||
249 | $Result1 = $xoopsDB->queryF($insertSQL); |
||
250 | dprt('SQL result = ' . $Result1, _INF); |
||
251 | |||
252 | // add xoopsUsers (not anon) to group if selected by Admin in config |
||
253 | if (!empty($pp_varlist['custom']) |
||
254 | && (('Yes' === $pp_varlist['option_selection1']) |
||
255 | || ('1' == $tr_config['don_forceadd']))) { |
||
256 | $memberHandler = xoops_getHandler('member'); |
||
257 | $edituser = $memberHandler->getUser($pp_varlist['custom']); |
||
258 | |||
259 | // add the user to specified group |
||
260 | if ($tr_config['assign_group']) { // config option set to add users to a group |
||
261 | $groupHandler = xoops_getHandler('group'); |
||
262 | $validGroup = $groupHandler->get((int)$tr_config['assign_group']); // make sure this is a valid group id |
||
263 | if ($validGroup) { |
||
264 | $thisUserGroups = $memberHandler->getGroupsByUser((int)$edituser->getVar('uid')); |
||
265 | if (!in_array($validGroup->getVar('groupid'), $thisUserGroups)) { |
||
266 | $success = $memberHandler->addUserToGroup($validGroup->getVar('groupid'), $edituser->getVar('uid')); |
||
267 | if ($success) { |
||
268 | dprt('User ' . $edituser->getVar('uname') . ' was added to the ' . $validGroup->getVar('name') . ' group', _INF); |
||
269 | } else { |
||
270 | dprt('User ' . $edituser->getVar('uname') . ' could not be addded to the ' . $validGroup->getVar('name') . ' group', _ERR); |
||
271 | } |
||
272 | } else { |
||
273 | dprt($edituser->getVar('uname') . ' is already in the ' . $validGroup->getVar('name') . ' group', _INF); |
||
274 | } |
||
275 | } else { |
||
276 | dprt('Group isn\'t valid - change Admin configs option<br>', _ERR); |
||
277 | } |
||
278 | } |
||
279 | |||
280 | // add the user to a specific rank |
||
281 | if ($tr_config['assign_rank']) { // config option set to add users to a rank |
||
282 | $urank = $edituser->rank(); |
||
283 | if (0 != $urank['id']) { |
||
284 | $result = $xoopsDB->query('SELECT COUNT(*) FROM ' . $xoopsDB->prefix('ranks') . " WHERE rank_id='" . $urank['id'] . "' AND rank_special=0"); |
||
285 | list($rank_check) = $xoopsDB->fetchRow($result); |
||
286 | $xoopsDB->freeRecordSet($result); |
||
287 | } else { |
||
288 | $rank_check = 1; |
||
289 | } |
||
290 | if ($rank_check > 0) { |
||
291 | // set user's new rank |
||
292 | $edituser->setVar('rank', $tr_config['assign_rank']); |
||
293 | $memberHandler->insertUser($edituser); |
||
294 | } |
||
295 | } |
||
296 | } |
||
297 | break; |
||
298 | } else { // We're not interested in this transaction, so we're done |
||
299 | dprt(_MD_XDONATION_NOTINTERESTED, _ERR); |
||
300 | foreach ($_POST as $key => $val) { |
||
301 | dprt("$key => $val", _ERR); |
||
302 | } |
||
303 | dprt('pp_varlist:', _ERR); |
||
304 | foreach ($pp_varlist as $key => $val) { |
||
305 | dprt("$key => $val", _ERR); |
||
306 | } |
||
307 | dprt('strcmp payment_status: ' . strcmp($pp_varlist['payment_status'], 'Completed'), _ERR); |
||
308 | dprt('strcmp txn_type: ' . strcmp($pp_varlist['txn_type'], 'web_accept'), _ERR); |
||
309 | dprt('strcmp txn_type: ' . strcmp($pp_varlist['txn_type'], 'send_money'), _ERR); |
||
310 | break; |
||
311 | } |
||
312 | } elseif (0 == strcmp($res, 'INVALID')) { |
||
313 | // log for manual investigation |
||
314 | dprt(_MD_XDONATION_INVALIDIPN, _ERR); |
||
315 | foreach ($_POST as $key => $val) { |
||
316 | dprt("$key => $val", _ERR); |
||
317 | } |
||
318 | break; |
||
319 | } else { |
||
320 | dprt(_MD_XDONATION_ERR_UNKNOWN_IPN_STAT, _ERR); |
||
321 | } |
||
322 | } |
||
323 | |||
324 | if ($dbg) { |
||
325 | $sql = 'SELECT * FROM ' . $xoopsDB->prefix('donations_transactions') . ' LIMIT 10'; |
||
326 | dprt(_MD_XDONATION_EXECUTING_QUERY, _INF); |
||
327 | $Result1 = $xoopsDB->query($sql); |
||
328 | if ($Result1) { |
||
329 | dprt('<span style="font-weight: bold; color: #00CC00;">' . _MD_XDONATION_DEBUGPASS . '</span>', _INF); |
||
330 | } else { |
||
331 | dprt('<span style="font-weight: bold; color: #CC0000;">' . _MD_XDONATION_DEBUGFAIL . '</span>', _ERR); |
||
332 | } |
||
333 | dprt(sprintf(_MD_XDONATION_RCVEMAIL, $tr_config['receiver_email']), _INF); |
||
334 | } |
||
335 | |||
336 | if ($log) { |
||
337 | dprt('<br>' . _MD_XDONATION_LOGBEGIN . "<br>\n", _INF); |
||
338 | // Insert the log entry |
||
339 | $currentDate = strftime('%Y-%m-%d %H:%M:%S', time()); |
||
340 | $paymentDate = isset($_POST['payment_date']) ? strftime('%Y-%m-%d %H:%M:%S', strtotime($_POST['payment_date'])) : $currentDate; |
||
341 | $sql = 'INSERT INTO ' . $xoopsDB->prefix('donations_translog') . " VALUES (NULL,'{$currentDate}', '{$paymentDate}','" . addslashes($log) . "')"; |
||
342 | $Result1 = $xoopsDB->queryF($sql); |
||
343 | |||
344 | // Clear out old log entries |
||
345 | $sql = 'SELECT COUNT(*) FROM ' . $xoopsDB->prefix('donations_translog'); |
||
346 | $Result1 = $xoopsDB->query($sql); |
||
347 | list($countLogs) = $xoopsDB->fetchRow($Result1); |
||
348 | if ($countLogs == $tr_config['ipn_log_entries']) { |
||
349 | $sql = 'DELETE FROM ' . $xoopsDB->prefix('donations_translog'); |
||
350 | $Result1 = $xoopsDB->queryF($sql); |
||
351 | if (false === $Result1) { |
||
352 | dprt(_MD_XDONATION_ERR_TXN_NOCLEAR, _ERR); |
||
353 | } else { |
||
354 | dprt(_MD_XDONATION_ERR_TXN_CLEAR, _INF); |
||
355 | } |
||
356 | } |
||
357 | } |
||
358 | |||
359 | fclose($fp); |
||
360 | if ($lp) { |
||
361 | fwrite($lp, _MD_XDONATION_EXITING . "\n"); |
||
362 | fclose($lp); |
||
363 | } |
||
364 | |||
365 | if ($dbg) { |
||
366 | echo '<hr>'; |
||
367 | echo _MD_XDONATION_IFNOERROR . "<br>\n"; |
||
368 | echo "<a href='javascript:window.close();'>Close Window</a>"; |
||
369 | } |
||
370 | |||
371 | /** |
||
372 | * |
||
373 | * Debug Message Store/Display |
||
374 | * @param string $str string to store/display |
||
375 | * @param int $clvl error reporting level (1 = error, 2= info) |
||
376 | */ |
||
377 | function dprt($str, $clvl) |
||
378 | { |
||
379 | global $dbg, $lp, $log, $loglvl; |
||
380 | |||
381 | if (isset($dbg) && $dbg) { |
||
382 | echo $str . '<br>'; |
||
383 | } |
||
384 | |||
385 | if (isset($loglvl) && ($clvl <= $loglvl)) { |
||
386 | $log .= $str . "\n"; |
||
387 | if (isset($lp) && $lp) { |
||
388 | fwrite($lp, strip_tags($str) . "\r\n"); |
||
389 | } |
||
390 | } |
||
391 | } |
||
392 |