subscriptions.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. <?php
  2. /**
  3. * Simple Machines Forum (SMF)
  4. *
  5. * @package SMF
  6. * @author Simple Machines http://www.simplemachines.org
  7. * @copyright 2011 Simple Machines
  8. * @license http://www.simplemachines.org/about/smf/license.php BSD
  9. *
  10. * @version 2.0
  11. */
  12. /*
  13. This file is the file which all subscription gateways should call
  14. when a payment has been received - it sorts out the user status.
  15. void generateSubscriptionError()
  16. // log the error for posterity
  17. */
  18. // Start things rolling by getting SMF alive...
  19. if (!file_exists(dirname(__FILE__) . '/SSI.php'))
  20. die('Cannot find SSI.php');
  21. require_once(dirname(__FILE__) . '/SSI.php');
  22. require_once($sourcedir . '/ManagePaid.php');
  23. // For any admin emailing.
  24. require_once($sourcedir . '/Subs-Admin.php');
  25. loadLanguage('ManagePaid');
  26. // If there's literally nothing coming in, let's take flight!
  27. if (empty($_POST))
  28. die($txt['paid_no_data']);
  29. // I assume we're even active?
  30. if (empty($modSettings['paid_enabled']))
  31. exit;
  32. // If we have some custom people who find out about problems load them here.
  33. $notify_users = array();
  34. if (!empty($modSettings['paid_email_to']))
  35. foreach (explode(',', $modSettings['paid_email_to']) as $email)
  36. $notify_users[] = array(
  37. 'email' => $email,
  38. 'name' => $txt['who_member'],
  39. 'id' => 0,
  40. );
  41. // We need to see whether we can find the correct payment gateway,
  42. // we'll going to go through all our gateway scripts and find out
  43. // if they are happy with what we have.
  44. $txnType = '';
  45. $gatewayHandles = loadPaymentGateways();
  46. foreach ($gatewayHandles as $gateway)
  47. {
  48. $gatewayClass = new $gateway['payment_class']();
  49. if ($gatewayClass->isValid())
  50. {
  51. $txnType = $gateway['code'];
  52. break;
  53. }
  54. }
  55. if (empty($txnType))
  56. generateSubscriptionError($txt['paid_unknown_transaction_type']);
  57. // Get the subscription and member ID amoungst others...
  58. @list ($subscription_id, $member_id) = $gatewayClass->precheck();
  59. // Integer these just in case.
  60. $subscription_id = (int) $subscription_id;
  61. $member_id = (int) $member_id;
  62. // This would be bad...
  63. if (empty($member_id))
  64. generateSubscriptionError($txt['paid_empty_member']);
  65. // Verify the member.
  66. $request = $smcFunc['db_query']('', '
  67. SELECT id_member, member_name, real_name, email_address
  68. FROM {db_prefix}members
  69. WHERE id_member = {int:current_member}',
  70. array(
  71. 'current_member' => $member_id,
  72. )
  73. );
  74. // Didn't find them?
  75. if ($smcFunc['db_num_rows']($request) == 0)
  76. generateSubscriptionError(sprintf($txt['paid_could_not_find_member'], $member_id));
  77. $member_info = $smcFunc['db_fetch_assoc']($request);
  78. $smcFunc['db_free_result']($request);
  79. // Get the subscription details.
  80. $request = $smcFunc['db_query']('', '
  81. SELECT cost, length, name
  82. FROM {db_prefix}subscriptions
  83. WHERE id_subscribe = {int:current_subscription}',
  84. array(
  85. 'current_subscription' => $subscription_id,
  86. )
  87. );
  88. // Didn't find it?
  89. if ($smcFunc['db_num_rows']($request) == 0)
  90. generateSubscriptionError(sprintf($txt['paid_count_not_find_subscription'], $member_id, $subscription_id));
  91. $subscription_info = $smcFunc['db_fetch_assoc']($request);
  92. $smcFunc['db_free_result']($request);
  93. // We wish to check the pending payments to make sure we are expecting this.
  94. $request = $smcFunc['db_query']('', '
  95. SELECT id_sublog, payments_pending, pending_details, end_time
  96. FROM {db_prefix}log_subscribed
  97. WHERE id_subscribe = {int:current_subscription}
  98. AND id_member = {int:current_member}
  99. LIMIT 1',
  100. array(
  101. 'current_subscription' => $subscription_id,
  102. 'current_member' => $member_id,
  103. )
  104. );
  105. if ($smcFunc['db_num_rows']($request) == 0)
  106. generateSubscriptionError(sprintf($txt['paid_count_not_find_subscription_log'], $member_id, $subscription_id));
  107. $subscription_info += $smcFunc['db_fetch_assoc']($request);
  108. $smcFunc['db_free_result']($request);
  109. // Is this a refund etc?
  110. if ($gatewayClass->isRefund())
  111. {
  112. // If the end time subtracted by current time, is not greater
  113. // than the duration (ie length of subscription), then we close it.
  114. if ($subscription_info['end_time'] - time() < $subscription_info['length'])
  115. {
  116. // Delete user subscription.
  117. removeSubscription($subscription_id, $member_id);
  118. $subscription_act = time();
  119. $status = 0;
  120. }
  121. else
  122. {
  123. loadSubscriptions();
  124. $subscription_act = $subscription_info['end_time'] - $context['subscriptions'][$subscription_id]['num_length'];
  125. $status = 1;
  126. }
  127. // Mark it as complete so we have a record.
  128. $smcFunc['db_query']('', '
  129. UPDATE {db_prefix}log_subscribed
  130. SET end_time = {int:current_time}
  131. WHERE id_subscribe = {int:current_subscription}
  132. AND id_member = {int:current_member}
  133. AND status = {int:status}',
  134. array(
  135. 'current_time' => $subscription_act,
  136. 'current_subscription' => $subscription_id,
  137. 'current_member' => $member_id,
  138. 'status' => $status,
  139. )
  140. );
  141. // Receipt?
  142. if (!empty($modSettings['paid_email']) && $modSettings['paid_email'] == 2)
  143. {
  144. $replacements = array(
  145. 'NAME' => $subscription_info['name'],
  146. 'REFUNDNAME' => $member_info['member_name'],
  147. 'REFUNDUSER' => $member_info['real_name'],
  148. 'PROFILELINK' => $scripturl . '?action=profile;u=' . $member_id,
  149. 'DATE' => timeformat(time(), false),
  150. );
  151. emailAdmins('paid_subscription_refund', $replacements, $notify_users);
  152. }
  153. }
  154. // Otherwise is it what we want, a purchase?
  155. elseif ($gatewayClass->isPayment() || $gatewayClass->isSubscription())
  156. {
  157. $cost = unserialize($subscription_info['cost']);
  158. $total_cost = $gatewayClass->getCost();
  159. $notify = false;
  160. // For one off's we want to only capture them once!
  161. if (!$gatewayClass->isSubscription())
  162. {
  163. $real_details = @unserialize($subscription_info['pending_details']);
  164. if (empty($real_details))
  165. generateSubscriptionError(sprintf($txt['paid_count_not_find_outstanding_payment'], $member_id, $subscription_id));
  166. // Now we just try to find anything pending.
  167. // We don't really care which it is as security happens later.
  168. foreach ($real_details as $id => $detail)
  169. {
  170. unset($real_details[$id]);
  171. if ($detail[3] == 'payback' && $subscription_info['payments_pending'])
  172. $subscription_info['payments_pending']--;
  173. break;
  174. }
  175. $subscription_info['pending_details'] = empty($real_details) ? '' : serialize($real_details);
  176. $smcFunc['db_query']('', '
  177. UPDATE {db_prefix}log_subscribed
  178. SET payments_pending = {int:payments_pending}, pending_details = {string:pending_details}
  179. WHERE id_sublog = {int:current_subscription_item}',
  180. array(
  181. 'payments_pending' => $subscription_info['payments_pending'],
  182. 'current_subscription_item' => $subscription_info['id_sublog'],
  183. 'pending_details' => $subscription_info['pending_details'],
  184. )
  185. );
  186. }
  187. // Is this flexible?
  188. if ($subscription_info['length'] == 'F')
  189. {
  190. $found_duration = 0;
  191. // This is a little harder, can we find the right duration?
  192. foreach ($cost as $duration => $value)
  193. {
  194. if ($duration == 'fixed')
  195. continue;
  196. elseif ((float) $value == (float) $total_cost)
  197. $found_duration = strtoupper(substr($duration, 0, 1));
  198. }
  199. // If we have the duration then we're done.
  200. if ($found_duration!== 0)
  201. {
  202. $notify = true;
  203. addSubscription($subscription_id, $member_id, $found_duration);
  204. }
  205. }
  206. else
  207. {
  208. $actual_cost = $cost['fixed'];
  209. // It must be at least the right amount.
  210. if ($total_cost != 0 && $total_cost >= $actual_cost)
  211. {
  212. // Add the subscription.
  213. $notify = true;
  214. addSubscription($subscription_id, $member_id);
  215. }
  216. }
  217. // Send a receipt?
  218. if (!empty($modSettings['paid_email']) && $modSettings['paid_email'] == 2 && $notify)
  219. {
  220. $replacements = array(
  221. 'NAME' => $subscription_info['name'],
  222. 'SUBNAME' => $member_info['member_name'],
  223. 'SUBUSER' => $member_info['real_name'],
  224. 'SUBEMAIL' => $member_info['email_address'],
  225. 'PRICE' => sprintf($modSettings['paid_currency_symbol'], $total_cost),
  226. 'PROFILELINK' => $scripturl . '?action=profile;u=' . $member_id,
  227. 'DATE' => timeformat(time(), false),
  228. );
  229. emailAdmins('paid_subscription_new', $replacements, $notify_users);
  230. }
  231. }
  232. // In case we have anything specific to do.
  233. $gatewayClass->close();
  234. // Log an error then die.
  235. function generateSubscriptionError($text)
  236. {
  237. global $modSettings, $notify_users, $smcFunc;
  238. // Send an email?
  239. if (!empty($modSettings['paid_email']))
  240. {
  241. $replacements = array(
  242. 'ERROR' => $text,
  243. );
  244. emailAdmins('paid_subscription_error', $replacements, $notify_users);
  245. }
  246. // Maybe we can try to give them the post data?
  247. if (!empty($_POST))
  248. foreach ($_POST as $key => $val)
  249. $text .= '<br />' . $smcFunc['htmlspecialchars']($key) . ': ' . $smcFunc['htmlspecialchars']($val);
  250. // Then just log and die.
  251. log_error($text);
  252. exit;
  253. }
  254. ?>