comparison forum/Sources/Subscriptions-PayPal.php @ 76:e3e11437ecea website

Add forum code
author Chris Cannam
date Sun, 07 Jul 2013 11:25:48 +0200
parents
children
comparison
equal deleted inserted replaced
75:72f59aa7e503 76:e3e11437ecea
1 <?php
2
3 /**
4 * Simple Machines Forum (SMF)
5 *
6 * @package SMF
7 * @author Simple Machines http://www.simplemachines.org
8 * @copyright 2011 Simple Machines
9 * @license http://www.simplemachines.org/about/smf/license.php BSD
10 *
11 * @version 2.0.3
12 */
13
14 // This won't be dedicated without this - this must exist in each gateway!
15 // SMF Payment Gateway: paypal
16
17 if (!defined('SMF'))
18 die('Hacking attempt...');
19
20 class paypal_display
21 {
22 public $title = 'PayPal';
23
24 public function getGatewaySettings()
25 {
26 global $txt;
27
28 $setting_data = array(
29 array('text', 'paypal_email', 'subtext' => $txt['paypal_email_desc']),
30 );
31
32 return $setting_data;
33 }
34
35 // Is this enabled for new payments?
36 public function gatewayEnabled()
37 {
38 global $modSettings;
39
40 return !empty($modSettings['paypal_email']);
41 }
42
43 // What do we want?
44 public function fetchGatewayFields($unique_id, $sub_data, $value, $period, $return_url)
45 {
46 global $modSettings, $txt, $boardurl;
47
48 $return_data = array(
49 'form' => 'https://www.' . (!empty($modSettings['paidsubs_test']) ? 'sandbox.' : '') . 'paypal.com/cgi-bin/webscr',
50 'id' => 'paypal',
51 'hidden' => array(),
52 'title' => $txt['paypal'],
53 'desc' => $txt['paid_confirm_paypal'],
54 'submit' => $txt['paid_paypal_order'],
55 'javascript' => '',
56 );
57
58 // All the standard bits.
59 $return_data['hidden']['business'] = $modSettings['paypal_email'];
60 $return_data['hidden']['item_name'] = $sub_data['name'] . ' ' . $txt['subscription'];
61 $return_data['hidden']['item_number'] = $unique_id;
62 $return_data['hidden']['currency_code'] = strtoupper($modSettings['paid_currency_code']);
63 $return_data['hidden']['no_shipping'] = 1;
64 $return_data['hidden']['no_note'] = 1;
65 $return_data['hidden']['amount'] = $value;
66 $return_data['hidden']['cmd'] = !$sub_data['repeatable'] ? '_xclick' : '_xclick-subscriptions';
67 $return_data['hidden']['return'] = $return_url;
68 $return_data['hidden']['a3'] = $value;
69 $return_data['hidden']['src'] = 1;
70 $return_data['hidden']['notify_url'] = $boardurl . '/subscriptions.php';
71
72 // Now stuff dependant on what we're doing.
73 if ($sub_data['flexible'])
74 {
75 $return_data['hidden']['p3'] = 1;
76 $return_data['hidden']['t3'] = strtoupper(substr($period, 0, 1));
77 }
78 else
79 {
80 preg_match('~(\d*)(\w)~', $sub_data['real_length'], $match);
81 $unit = $match[1];
82 $period = $match[2];
83
84 $return_data['hidden']['p3'] = $unit;
85 $return_data['hidden']['t3'] = $period;
86 }
87
88 // If it's repeatable do soem javascript to respect this idea.
89 if (!empty($sub_data['repeatable']))
90 $return_data['javascript'] = '
91 document.write(\'<label for="do_paypal_recur"><input type="checkbox" name="do_paypal_recur" id="do_paypal_recur" checked="checked" onclick="switchPaypalRecur();" class="input_check" />' . $txt['paid_make_recurring'] . '</label><br />\');
92
93 function switchPaypalRecur()
94 {
95 document.getElementById("paypal_cmd").value = document.getElementById("do_paypal_recur").checked ? "_xclick-subscriptions" : "_xclick";
96 }';
97
98 return $return_data;
99 }
100 }
101
102 class paypal_payment
103 {
104 private $return_data;
105
106 // This function returns true/false for whether this gateway thinks the data is intended for it.
107 public function isValid()
108 {
109 global $modSettings;
110
111 // Has the user set up an email address?
112 if (empty($modSettings['paypal_email']))
113 return false;
114 // Check the correct transaction types are even here.
115 if ((!isset($_POST['txn_type']) && !isset($_POST['payment_status'])) || (!isset($_POST['business']) && !isset($_POST['receiver_email'])))
116 return false;
117 // Correct email address?
118 if (!isset($_POST['business']))
119 $_POST['business'] = $_POST['receiver_email'];
120 if ($modSettings['paypal_email'] != $_POST['business'] && (empty($modSettings['paypal_additional_emails']) || !in_array($_POST['business'], explode(',', $modSettings['paypal_additional_emails']))))
121 return false;
122 return true;
123 }
124
125 // Validate all the data was valid.
126 public function precheck()
127 {
128 global $modSettings, $txt;
129
130 // Put this to some default value.
131 if (!isset($_POST['txn_type']))
132 $_POST['txn_type'] = '';
133
134 // Build the request string - starting with the minimum requirement.
135 $requestString = 'cmd=_notify-validate';
136
137 // Now my dear, add all the posted bits.
138 foreach ($_POST as $k => $v)
139 $requestString .= '&' . $k . '=' . urlencode($v);
140
141 // Can we use curl?
142 if (function_exists('curl_init') && $curl = curl_init((!empty($modSettings['paidsubs_test']) ? 'https://www.sandbox.' : 'http://www.') . 'paypal.com/cgi-bin/webscr'))
143 {
144 // Set the post data.
145 curl_setopt($curl, CURLOPT_POST, true);
146 curl_setopt($curl, CURLOPT_POSTFIELDSIZE, 0);
147 curl_setopt($curl, CURLOPT_POSTFIELDS, $requestString);
148
149 curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
150 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 1);
151 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
152 curl_setopt($curl, CURLOPT_FORBID_REUSE, 1);
153 curl_setopt($curl, CURLOPT_HTTPHEADER, array(
154 'Host: www.' . (!empty($modSettings['paidsubs_test']) ? 'sandbox.' : '') . 'paypal.com',
155 'Connection: close'
156 ));
157
158 // Fetch the data returned as a string.
159 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
160
161 // Fetch the data.
162 $this->return_data = curl_exec($curl);
163
164 // Close the session.
165 curl_close($curl);
166 }
167 // Otherwise good old HTTP.
168 else
169 {
170 // Setup the headers.
171 $header = 'POST /cgi-bin/webscr HTTP/1.1' . "\r\n";
172 $header .= 'Content-Type: application/x-www-form-urlencoded' . "\r\n";
173 $header .= 'Host: www.' . (!empty($modSettings['paidsubs_test']) ? 'sandbox.' : '') . 'paypal.com' . "\r\n";
174 $header .= 'Content-Length: ' . strlen ($requestString) . "\r\n";
175 $header .= 'Connection: close' . "\r\n\r\n";
176
177 // Open the connection.
178 if (!empty($modSettings['paidsubs_test']))
179 $fp = fsockopen('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
180 else
181 $fp = fsockopen('www.paypal.com', 80, $errno, $errstr, 30);
182
183 // Did it work?
184 if (!$fp)
185 generateSubscriptionError($txt['paypal_could_not_connect']);
186
187 // Put the data to the port.
188 fputs($fp, $header . $requestString);
189
190 // Get the data back...
191 while (!feof($fp))
192 {
193 $this->return_data = fgets($fp, 1024);
194 if (strcmp(trim($this->return_data), 'VERIFIED') == 0)
195 break;
196 }
197
198 // Clean up.
199 fclose($fp);
200 }
201
202 // If this isn't verified then give up...
203 // !! This contained a comment "send an email", but we don't appear to send any?
204 if (strcmp(trim($this->return_data), 'VERIFIED') != 0)
205 exit;
206
207 // Check that this is intended for us.
208 if ($modSettings['paypal_email'] != $_POST['business'] && (empty($modSettings['paypal_additional_emails']) || !in_array($_POST['business'], explode(',', $modSettings['paypal_additional_emails']))))
209 exit;
210
211 // Is this a subscription - and if so it's it a secondary payment that we need to process?
212 if ($this->isSubscription() && (empty($_POST['item_number']) || strpos($_POST['item_number'], '+') === false))
213 // Calculate the subscription it relates to!
214 $this->_findSubscription();
215
216 // Verify the currency!
217 if (strtolower($_POST['mc_currency']) != $modSettings['paid_currency_code'])
218 exit;
219
220 // Can't exist if it doesn't contain anything.
221 if (empty($_POST['item_number']))
222 exit;
223
224 // Return the id_sub and id_member
225 return explode('+', $_POST['item_number']);
226 }
227
228 // Is this a refund?
229 public function isRefund()
230 {
231 if ($_POST['payment_status'] == 'Refunded' || $_POST['payment_status'] == 'Reversed' || $_POST['txn_type'] == 'Refunded' || ($_POST['txn_type'] == 'reversal' && $_POST['payment_status'] == 'Completed'))
232 return true;
233 else
234 return false;
235 }
236
237 // Is this a subscription?
238 public function isSubscription()
239 {
240 if (substr($_POST['txn_type'], 0, 14) == 'subscr_payment' && $_POST['payment_status'] == 'Completed')
241 return true;
242 else
243 return false;
244 }
245
246 // Is this a normal payment?
247 public function isPayment()
248 {
249 if ($_POST['payment_status'] == 'Completed' && $_POST['txn_type'] == 'web_accept')
250 return true;
251 else
252 return false;
253 }
254
255 // How much was paid?
256 public function getCost()
257 {
258 return (isset($_POST['tax']) ? $_POST['tax'] : 0) + $_POST['mc_gross'];
259 }
260
261 // exit.
262 public function close()
263 {
264 global $smcFunc, $subscription_id;
265
266 // If it's a subscription record the reference.
267 if ($_POST['txn_type'] == 'subscr_payment' && !empty($_POST['subscr_id']))
268 {
269 $_POST['subscr_id'] = $_POST['subscr_id'];
270 $smcFunc['db_query']('', '
271 UPDATE {db_prefix}log_subscribed
272 SET vendor_ref = {string:vendor_ref}
273 WHERE id_sublog = {int:current_subscription}',
274 array(
275 'current_subscription' => $subscription_id,
276 'vendor_ref' => $_POST['subscr_id'],
277 )
278 );
279 }
280
281 exit();
282 }
283
284 // A private function to find out the subscription details.
285 private function _findSubscription()
286 {
287 global $smcFunc;
288
289 // Assume we have this?
290 if (empty($_POST['subscr_id']))
291 return false;
292
293 // Do we have this in the database?
294 $request = $smcFunc['db_query']('', '
295 SELECT id_member, id_subscribe
296 FROM {db_prefix}log_subscribed
297 WHERE vendor_ref = {string:vendor_ref}
298 LIMIT 1',
299 array(
300 'vendor_ref' => $_POST['subscr_id'],
301 )
302 );
303 // No joy?
304 if ($smcFunc['db_num_rows']($request) == 0)
305 {
306 // Can we identify them by email?
307 if (!empty($_POST['payer_email']))
308 {
309 $smcFunc['db_free_result']($request);
310 $request = $smcFunc['db_query']('', '
311 SELECT ls.id_member, ls.id_subscribe
312 FROM {db_prefix}log_subscribed AS ls
313 INNER JOIN {db_prefix}members AS mem ON (mem.id_member = ls.id_member)
314 WHERE mem.email_address = {string:payer_email}
315 LIMIT 1',
316 array(
317 'payer_email' => $_POST['payer_email'],
318 )
319 );
320 if ($smcFunc['db_num_rows']($request) == 0)
321 return false;
322 }
323 else
324 return false;
325 }
326 list ($member_id, $subscription_id) = $smcFunc['db_fetch_row']($request);
327 $_POST['item_number'] = $member_id . '+' . $subscription_id;
328 $smcFunc['db_free_result']($request);
329 }
330 }
331
332 ?>