PageRenderTime 57ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/html/AppCode/expressionengine/modules/simple_commerce/mod.simple_commerce.php

https://github.com/w3bg/www.hsifin.com
PHP | 1080 lines | 1024 code | 27 blank | 29 comment | 17 complexity | 3552c17e74fda942f6a91549a13ce8a3 MD5 | raw file
Possible License(s): AGPL-3.0
  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * ExpressionEngine - by EllisLab
  4. *
  5. * @package ExpressionEngine
  6. * @author ExpressionEngine Dev Team
  7. * @copyright Copyright (c) 2003 - 2010, EllisLab, Inc.
  8. * @license http://expressionengine.com/user_guide/license.html
  9. * @link http://expressionengine.com
  10. * @since Version 2.0
  11. * @filesource
  12. */
  13. // ------------------------------------------------------------------------
  14. /**
  15. * ExpressionEngine Simple Commerce Module
  16. *
  17. * @package ExpressionEngine
  18. * @subpackage Modules
  19. * @category Modules
  20. * @author ExpressionEngine Dev Team
  21. * @link http://expressionengine.com
  22. */
  23. if ( ! defined('EXT'))
  24. {
  25. exit('Invalid file request');
  26. }
  27. class Simple_commerce {
  28. var $return_data = '';
  29. var $debug = FALSE;
  30. var $debug_incoming_ipn = FALSE; // Will send an email with the incoming ipn post data for debug purposes
  31. var $debug_email_address = ''; // Address to send the incoming ipn debug data to- defaults to webmaster_email
  32. var $possible_post;
  33. var $post = array();
  34. var $encrypt = FALSE;
  35. var $certificate_id = '';
  36. var $public_certificate = '';
  37. var $private_key = '';
  38. var $paypal_certificate = '';
  39. var $temp_path = '';
  40. /** ----------------------------------------
  41. /** Constructor
  42. /** ----------------------------------------*/
  43. function Simple_commerce()
  44. {
  45. // Make a local reference to the ExpressionEngine super object
  46. $this->EE =& get_instance();
  47. $this->possible_post = array('business', 'receiver_email', 'receiver_id', 'item_name',
  48. 'item_number', 'quantity', 'invoice', 'custom', 'memo',
  49. 'tax', 'option_name1', 'option_selection1', 'option_name2',
  50. 'option_selection2', 'num_cart_items', 'mc_gross', 'mc_fee',
  51. 'mc_currency', 'payment_gross', 'payment_fee',
  52. 'payment_status', 'pending_reason', 'reason_code',
  53. 'payment_date', 'txn_id', 'txn_type', 'payment_type',
  54. 'first_name', 'last_name',
  55. 'payer_business_name', 'address_name', 'address_street',
  56. 'address_city', 'address_state', 'address_zip', 'address_country_code',
  57. 'address_country', 'address_status', 'payer_email',
  58. 'payer_id', 'payer_status', 'member_id',
  59. 'verify_sign', 'test_ipn');
  60. if ($this->EE->config->item('sc_encrypt_buttons') === 'y' && function_exists('openssl_pkcs7_sign'))
  61. {
  62. $this->encrypt = TRUE;
  63. foreach(array('certificate_id', 'public_certificate', 'private_key', 'paypal_certificate') as $val)
  64. {
  65. if ($this->EE->config->item('sc_'.$val) === FALSE OR $this->EE->config->item('sc_'.$val) == '')
  66. {
  67. $this->encrypt = FALSE;
  68. break;
  69. }
  70. else
  71. {
  72. $this->$val = $this->EE->config->item('sc_'.$val);
  73. }
  74. }
  75. // Not required
  76. if ($this->encrypt === TRUE && $this->EE->config->item('sc_temp_path') !== FALSE)
  77. {
  78. $this->temp_path = $this->EE->config->item('sc_temp_path');
  79. }
  80. }
  81. }
  82. /** ----------------------------------------
  83. /** Output Item Info
  84. /** ----------------------------------------*/
  85. function purchase()
  86. {
  87. if (($entry_id = $this->EE->TMPL->fetch_param('entry_id')) === FALSE) return;
  88. if (($success = $this->EE->TMPL->fetch_param('success')) === FALSE) return;
  89. $cached = FALSE;
  90. $paypal_account = ( ! $this->EE->config->item('sc_paypal_account')) ? $this->EE->config->item('webmaster_email') : $this->EE->config->item('sc_paypal_account');
  91. $cancel = ( ! $this->EE->TMPL->fetch_param('cancel')) ? $this->EE->functions->fetch_site_index() : $this->EE->TMPL->fetch_param('cancel');
  92. $currency = ( ! $this->EE->TMPL->fetch_param('currency')) ? 'USD' : $this->EE->TMPL->fetch_param('currency');
  93. $country_code = ( ! $this->EE->TMPL->fetch_param('country_code')) ? 'US' : strtoupper($this->EE->TMPL->fetch_param('country_code'));
  94. $show_disabled = ( $this->EE->TMPL->fetch_param('show_disabled') == 'yes') ? TRUE : FALSE;
  95. if (substr($success, 0, 4) !== 'http')
  96. {
  97. $success = $this->EE->functions->create_url($success);
  98. }
  99. if (substr($cancel, 0, 4) !== 'http')
  100. {
  101. $cancel = $this->EE->functions->create_url($cancel);
  102. }
  103. if ($show_disabled === TRUE)
  104. {
  105. $addsql = '';
  106. }
  107. else
  108. {
  109. $addsql = "AND sci.item_enabled = 'y' ";
  110. }
  111. $query = $this->EE->db->query("SELECT wt.title AS item_name, sci.*
  112. FROM exp_simple_commerce_items sci, exp_channel_titles wt
  113. WHERE sci.entry_id = '".$this->EE->db->escape_str($entry_id)."'
  114. {$addsql}
  115. AND sci.entry_id = wt.entry_id
  116. LIMIT 1");
  117. if ($query->num_rows() == 0) return;
  118. $row = $query->row_array();
  119. $variable_row = $row;
  120. if ($this->encrypt !== TRUE)
  121. {
  122. $variable_row['item_name'] = str_replace( array("&","<",">","\"", "'", "-"),
  123. array("&amp;", "&lt;", "&gt;", "&quot;", "&apos;", "&#45;"),
  124. $row['item_name'] );
  125. }
  126. $variable_row['item_regular_price'] = $this->round_money($row['item_regular_price']);
  127. $variable_row['item_sale_price'] = $this->round_money($row['item_sale_price']);
  128. $variable_row['item_type'] = ($row['recurring'] == 'y') ? 'subscription' : 'purchase';
  129. $buy_now['action'] = ($this->debug === TRUE) ? 'https://www.sandbox.paypal.com/cgi-bin/webscr' : 'https://www.paypal.com/cgi-bin/webscr';
  130. $buy_now['hidden_fields'] = array(
  131. 'cmd' => '_xclick',
  132. 'upload' => "1",
  133. 'business' => $paypal_account,
  134. 'return' => $success,
  135. 'cancel_return' => $cancel,
  136. 'item_name' => $row['item_name'] ,
  137. 'item_number' => $row['item_id'] ,
  138. 'amount' => ($row['item_use_sale'] == 'y') ? $row['item_sale_price'] : $row['item_regular_price'] ,
  139. 'lc' => $country_code,
  140. 'currency_code' => $currency,
  141. 'custom' => $this->EE->session->userdata['member_id']
  142. );
  143. if ($this->encrypt === TRUE)
  144. {
  145. $url = $buy_now['action'].'?cmd=_s-xclick&amp;encrypted='.urlencode($this->encrypt_data($buy_now['hidden_fields']));
  146. }
  147. else
  148. {
  149. $url = $buy_now['action'];
  150. foreach($buy_now['hidden_fields'] as $k => $v)
  151. {
  152. $url .= ($k == 'cmd') ? '?'.$k.'='.$v : '&amp;'.$k.'='.$this->prep_val($v);
  153. }
  154. }
  155. $variable_row['buy_now_url'] = $url;
  156. // Subscription
  157. $subscribe['action'] = ($this->debug === TRUE) ? 'https://www.sandbox.paypal.com/cgi-bin/webscr' : 'https://www.paypal.com/cgi-bin/webscr';
  158. $subscribe['hidden_fields'] = array(
  159. 'cmd' => '_xclick-subscriptions',
  160. 'upload' => "1",
  161. 'business' => $paypal_account,
  162. 'return' => $success,
  163. 'cancel_return' => $cancel,
  164. 'item_name' => $row['item_name'],
  165. 'item_number' => $row['item_id'],
  166. 'p3' => $row['subscription_frequency'],
  167. 't3' => strtoupper(substr($row['subscription_frequency_unit'], 0, 1)),
  168. 'a3' => ($row['item_use_sale'] == 'y') ? $row['item_sale_price'] : $row['item_regular_price'],
  169. 'src' => 1,
  170. 'lc' => $country_code,
  171. 'currency_code' => $currency,
  172. 'custom' => $this->EE->session->userdata['member_id']
  173. );
  174. if ($this->encrypt === TRUE)
  175. {
  176. $url = $subscribe['action'].'?cmd=_s-xclick&amp;encrypted='.urlencode($this->encrypt_data($buy_now['hidden_fields']));
  177. }
  178. else
  179. {
  180. $url = $subscribe['action'];
  181. foreach($subscribe['hidden_fields'] as $k => $v)
  182. {
  183. $url .= ($k == 'cmd') ? '?'.$k.'='.$v : '&amp;'.$k.'='.$this->prep_val($v);
  184. }
  185. }
  186. $variable_row['subscribe_now_url'] = $url;
  187. // Add to Cart
  188. $add_to_cart['action'] = ($this->debug === TRUE) ? 'https://www.sandbox.paypal.com/cgi-bin/webscr' : 'https://www.paypal.com/cgi-bin/webscr';
  189. $add_to_cart['hidden_fields'] = array(
  190. 'cmd' => '_cart',
  191. 'add' => "1",
  192. 'business' => $paypal_account,
  193. 'return' => $success,
  194. 'cancel_return' => $cancel,
  195. 'item_name' => $row['item_name'],
  196. 'item_number' => $row['item_id'],
  197. 'quantity' => '1',
  198. 'amount' => ($row['item_use_sale'] == 'y') ? $row['item_sale_price'] : $row['item_regular_price'],
  199. 'lc' => $country_code,
  200. 'currency_code' => $currency,
  201. 'custom' => $this->EE->session->userdata['member_id']
  202. );
  203. if ($this->encrypt === TRUE)
  204. {
  205. $url = $add_to_cart['action'].'?cmd=_s-xclick&amp;encrypted='.urlencode($this->encrypt_data($add_to_cart['hidden_fields']));
  206. }
  207. else
  208. {
  209. $url = $add_to_cart['action'];
  210. foreach($add_to_cart['hidden_fields'] as $k => $v)
  211. {
  212. $url .= ($k == 'cmd') ? '?'.$k.'='.$v : '&amp;'.$k.'='.$this->prep_val($v);
  213. }
  214. }
  215. $variable_row['add_to_cart_url'] = $url;
  216. // View Cart
  217. if ($this->debug === TRUE)
  218. {
  219. $view_cart['action'] = 'https://www.sandbox.paypal.com/cart/display=1&amp;bn=tm_gl_2.0&amp;business='.$paypal_account;
  220. }
  221. else
  222. {
  223. $view_cart['action'] = 'https://www.paypal.com/cart/display=1&amp;bn=tm_gl_2.0&amp;business='.$paypal_account;
  224. }
  225. $variable_row['view_cart_url'] = $view_cart['action'];
  226. /** ----------------------------------------
  227. /** Parse the Buttons
  228. /** ----------------------------------------*/
  229. if ($this->encrypt === TRUE)
  230. {
  231. $buy_now['hidden_fields'] = array('cmd' => '_s-xclick',
  232. 'encrypted' => $this->encrypt_data($buy_now['hidden_fields']));
  233. $add_to_cart['hidden_fields'] = array('cmd' => '_s-xclick',
  234. 'encrypted' => $this->encrypt_data($add_to_cart['hidden_fields']));
  235. }
  236. $variables[] = $variable_row;
  237. $output = $this->EE->TMPL->parse_variables($this->EE->TMPL->tagdata, $variables);
  238. foreach ($this->EE->TMPL->var_pair as $key => $val)
  239. {
  240. $data = array();
  241. if ($key == 'buy_now_button')
  242. {
  243. $data = $buy_now;
  244. }
  245. elseif ($key == 'add_to_cart_button' && $row['recurring'] != 'y')
  246. {
  247. $data = $add_to_cart;
  248. }
  249. elseif ($key == 'view_cart_button' && $row['recurring'] != 'y')
  250. {
  251. $data = $view_cart;
  252. }
  253. else
  254. {
  255. $output = $this->EE->TMPL->delete_var_pairs($key, $key, $output);
  256. continue;
  257. }
  258. $data['id'] = 'paypal_form_'.$row['item_id'].'_'.$key;
  259. $data['secure'] = FALSE;
  260. $form = $this->EE->functions->form_declaration($data).
  261. '<input type="submit" name="submit" value="\\1" class="paypal_button" />'."\n".
  262. '</form>'."\n\n";
  263. $output = preg_replace("/".LD.preg_quote($key).RD."(.*?)".LD.'\/'.$key.RD."/s", $form, $output);
  264. }
  265. $this->return_data = $output;
  266. return $this->return_data;
  267. }
  268. function button_form($id, $type, $hidden='')
  269. {
  270. $data['id'] = 'paypal_form_'.$row['item_id'].'_'.$type;
  271. $data['class'] = $this->EE->TMPL->form_class;
  272. $data['secure'] = FALSE;
  273. $data = $hidden;
  274. $form = $this->EE->functions->form_declaration($data).
  275. '<input type="submit" name="submit" value="\\1" class="paypal_button" />'."\n".
  276. '</form>'."\n\n";
  277. return 'dude';
  278. }
  279. /** -------------------------------------
  280. /** Round Money
  281. /** -------------------------------------*/
  282. function round_money($value, $dec=2)
  283. {
  284. $decimal = ($this->EE->TMPL->fetch_param('decimal') == ',') ? ',' : '.';
  285. $value += 0.0;
  286. $unit = floor($value * pow(10, $dec+1)) / 10;
  287. $round = round($unit);
  288. return str_replace('.', $decimal, sprintf("%01.2f", ($round / pow(10, $dec))));
  289. }
  290. /** ----------------------------------------
  291. /** Process an Incoming IPN From PayPal
  292. /** ----------------------------------------*/
  293. function incoming_ipn()
  294. {
  295. // Send incoming post data if debugging required
  296. if ($this->debug_incoming_ipn)
  297. {
  298. ob_start();
  299. print_r($_POST);
  300. $msg = ob_get_contents();
  301. ob_end_clean();
  302. $this->EE->load->library('email');
  303. $debug_to = ($this->debug_email_address == '') ? $this->EE->config->item('webmaster_email') : $this->debug_email_address;
  304. $this->EE->email->from($this->EE->config->item('webmaster_email'),
  305. $this->EE->config->item('site_name'));
  306. $this->EE->email->to($debug_to);
  307. $this->EE->email->subject('EE Debug: Incoming IPN Response');
  308. $this->EE->email->message($msg);
  309. $this->EE->email->send();
  310. $this->EE->email->EE_initialize();
  311. }
  312. if (empty($_POST))
  313. {
  314. @header("HTTP/1.0 404 Not Found");
  315. @header("HTTP/1.1 404 Not Found");
  316. exit('No Data Sent');
  317. }
  318. elseif($this->debug !== TRUE && isset($_POST['test_ipn']) && $_POST['test_ipn'] == 1)
  319. {
  320. @header("HTTP/1.0 404 Not Found");
  321. @header("HTTP/1.1 404 Not Found");
  322. exit('Not Debugging Right Now');
  323. }
  324. $paypal_account = ( ! $this->EE->config->item('sc_paypal_account')) ? $this->EE->config->item('webmaster_email') : $this->EE->config->item('sc_paypal_account');
  325. /** ----------------------------------------
  326. /** Prep, Prep, Prep
  327. /** ----------------------------------------*/
  328. foreach($this->possible_post as $value)
  329. {
  330. $this->post[$value] = '';
  331. }
  332. foreach($_POST as $key => $value)
  333. {
  334. $this->post[$key] = $this->EE->security->xss_clean($value);
  335. }
  336. if ($this->debug === TRUE)
  337. {
  338. $url = ( ! function_exists('openssl_open')) ? 'http://www.sandbox.paypal.com/cgi-bin/webscr' : 'https://www.sandbox.paypal.com/cgi-bin/webscr';
  339. }
  340. else
  341. {
  342. $url = ( ! function_exists('openssl_open')) ? 'http://www.paypal.com/cgi-bin/webscr' : 'https://www.paypal.com/cgi-bin/webscr';
  343. }
  344. /** ----------------------------------------
  345. /** Ping Them Back For Confirmation
  346. /** ----------------------------------------*/
  347. if ( function_exists('curl_init'))
  348. {
  349. $result = $this->curl_process($url);
  350. }
  351. else
  352. {
  353. $result = $this->fsockopen_process($url);
  354. }
  355. /** ----------------------------------------
  356. /** Evaluate PayPal's Response
  357. /** ----------------------------------------*/
  358. /* -------------------------------------
  359. /* 'simple_commerce_evaluate_ipn_response' hook.
  360. /* - Take over processing of PayPal's response to an
  361. /* - IPN confirmation
  362. /* - Added EE 1.5.1
  363. */
  364. if ($this->EE->extensions->active_hook('simple_commerce_evaluate_ipn_response') === TRUE)
  365. {
  366. $result = $this->EE->extensions->universal_call('simple_commerce_evaluate_ipn_response', $this, $result);
  367. if ($this->EE->extensions->end_script === TRUE) return;
  368. }
  369. /*
  370. /* -------------------------------------*/
  371. if (stristr($result, 'VERIFIED'))
  372. {
  373. // Subscription start and end pings have no payment status, so that check not included
  374. // Not our paypal account receiving money, so invalid - and we key off txn_type for our conditional handling
  375. if (strtolower($paypal_account) != trim($this->post['receiver_email']) OR ! isset($this->post['txn_type']))
  376. {
  377. return FALSE;
  378. }
  379. // User Valid?
  380. $this->EE->db->select('screen_name');
  381. $this->EE->db->where('member_id', $this->post['custom']);
  382. $query = $this->EE->db->get('exp_members');
  383. if ($query->num_rows() == 0) return FALSE;
  384. $this->post['screen_name'] = $query->row('screen_name') ;
  385. /** --------------------------------------------
  386. /** The Subscription Types We Care About
  387. /** - According to numerous posts around the internet, these are the only two we should really care about
  388. /** --------------------------------------------*/
  389. if (in_array($this->post['txn_type'], array('subscr_signup', 'subscr_eot', 'subscr_cancel')))
  390. {
  391. if ( ! isset($this->post['subscr_id']))
  392. {
  393. return FALSE;
  394. }
  395. // Successful Subscription Data- send it on!
  396. if(isset($this->post['item_number']) && $this->post['item_number'] != '' && is_numeric($this->post['mc_amount3']) && $this->post['mc_amount3'] > 0)
  397. {
  398. $this->perform_actions($this->post['item_number'], '', '', '', $this->post['txn_type']);
  399. }
  400. }
  401. elseif (in_array($this->post['txn_type'], array('cart', 'web_accept')))
  402. {
  403. // Is this a repeat, perhaps?
  404. // Note- subscription signups do not have a txn_id so we check only non-subscriptions
  405. $query = $this->EE->db->query("SELECT COUNT(*) AS count FROM exp_simple_commerce_purchases
  406. WHERE txn_id = '".$this->EE->db->escape_str($this->post['txn_id'])."'");
  407. $this->EE->db->where('txn_id', $this->post['txn_id']);
  408. $this->EE->db->from('exp_simple_commerce_purchases');
  409. if ($this->EE->db->count_all_results() > 0) return FALSE;
  410. //A regular purchase should be completed at this point
  411. if (trim($this->post['payment_status']) != 'Completed')
  412. {
  413. return FALSE;
  414. }
  415. if ($this->post['num_cart_items'] != '' && $this->post['num_cart_items'] > 0 && isset($_POST['item_number1']))
  416. {
  417. for($i=1; $i <= $this->post['num_cart_items']; ++$i)
  418. {
  419. if (($item_id = $this->EE->input->get_post('item_number'.$i)) !== FALSE)
  420. {
  421. $qnty = (isset($_POST['quantity'.$i]) && is_numeric($_POST['quantity'.$i])) ? $_POST['quantity'.$i] : 1;
  422. $subtotal = (isset($_POST['mc_gross_'.$i]) && is_numeric(str_replace('.', '', $_POST['mc_gross_'.$i]))) ? $_POST['mc_gross_'.$i] : 0;
  423. if ($subtotal == 0)
  424. {
  425. continue;
  426. }
  427. $this->perform_actions($item_id, $qnty, $subtotal, $i);
  428. }
  429. }
  430. }
  431. elseif(isset($this->post['item_number']) && $this->post['item_number'] != '' && is_numeric($this->post['mc_gross']) && $this->post['mc_gross'] > 0)
  432. {
  433. $this->perform_actions($this->post['item_number'], $this->post['quantity'], $this->post['mc_gross']);
  434. }
  435. }
  436. else
  437. {
  438. return FALSE;
  439. }
  440. /** ------------------------------
  441. /** Paypal Suggests Sending a 200 OK Response Back
  442. /** ------------------------------*/
  443. @header("HTTP/1.0 200 OK");
  444. @header("HTTP/1.1 200 OK");
  445. exit('Success');
  446. }
  447. elseif (stristr($result, 'INVALID'))
  448. {
  449. // Error Checking?
  450. @header("HTTP/1.0 200 OK");
  451. @header("HTTP/1.1 200 OK");
  452. exit('Invalid');
  453. }
  454. }
  455. /** ----------------------------------------
  456. /** Sing a Song, Have a Dance
  457. /** ----------------------------------------*/
  458. function curl_process($url)
  459. {
  460. $postdata = 'cmd=_notify-validate';
  461. foreach ($_POST as $key => $value)
  462. {
  463. // str_replace("\n", "\r\n", $value)
  464. // put line feeds back to CR+LF as that's how PayPal sends them out
  465. // otherwise multi-line data will be rejected as INVALID
  466. $postdata .= "&$key=".urlencode(stripslashes(str_replace("\n", "\r\n", $value)));
  467. }
  468. $ch=curl_init();
  469. curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
  470. curl_setopt($ch,CURLOPT_URL,$url);
  471. curl_setopt($ch,CURLOPT_POST,1);
  472. curl_setopt($ch,CURLOPT_POSTFIELDS,$postdata);
  473. // Start ob to prevent curl_exec from displaying stuff.
  474. ob_start();
  475. curl_exec($ch);
  476. //Get contents of output buffer
  477. $info=ob_get_contents();
  478. curl_close($ch);
  479. //End ob and erase contents.
  480. ob_end_clean();
  481. return $info;
  482. }
  483. /** ----------------------------------------
  484. /** Drinking with Friends is Fun!
  485. /** ----------------------------------------*/
  486. function fsockopen_process($url)
  487. {
  488. $parts = parse_url($url);
  489. $host = $parts['host'];
  490. $path = ( ! isset($parts['path'])) ? '/' : $parts['path'];
  491. $port = ($parts['scheme'] == "https") ? '443' : '80';
  492. $ssl = ($parts['scheme'] == "https") ? 'ssl://' : '';
  493. if (isset($parts['query']) && $parts['query'] != '')
  494. {
  495. $path .= '?'.$parts['query'];
  496. }
  497. $postdata = 'cmd=_notify-validate';
  498. foreach ($_POST as $key => $value)
  499. {
  500. // str_replace("\n", "\r\n", $value)
  501. // put line feeds back to CR+LF as that's how PayPal sends them out
  502. // otherwise multi-line data will be rejected as INVALID
  503. $postdata .= "&$key=".urlencode(stripslashes(str_replace("\n", "\r\n", $value)));
  504. }
  505. $info = '';
  506. $fp = @fsockopen($ssl.$host, $port, $error_num, $error_str, 8);
  507. if (is_resource($fp))
  508. {
  509. fputs($fp, "POST {$path} HTTP/1.0\r\n");
  510. fputs($fp, "Host: {$host}\r\n");
  511. fputs($fp, "Content-Type: application/x-www-form-urlencoded\r\n");
  512. fputs($fp, "Content-Length: ".strlen($postdata)."\r\n");
  513. fputs($fp, "Connection: close\r\n\r\n");
  514. fputs($fp, $postdata . "\r\n\r\n");
  515. while($datum = fread($fp, 4096))
  516. {
  517. $info .= $datum;
  518. }
  519. @fclose($fp);
  520. }
  521. return $info;
  522. }
  523. /** ----------------------------------------
  524. /** Perform Store Item Actions
  525. /** ----------------------------------------*/
  526. function perform_actions($item_id, $qnty, $subtotal, $num_in_cart='', $type='')
  527. {
  528. $query = $this->EE->db->query("SELECT wt.title as item_name, sc.*
  529. FROM exp_simple_commerce_items sc, exp_channel_titles wt
  530. WHERE sc.entry_id = wt.entry_id
  531. AND sc.item_id = '".$this->EE->db->escape_str($item_id)."'");
  532. if ($query->num_rows() != 1)
  533. {
  534. return;
  535. }
  536. $row = $query->row();
  537. $this->post['item_name'] = $row->item_name;
  538. $this->post['item_number'] = $item_id;
  539. $this->post['quantity'] = $qnty;
  540. $this->post['mc_gross'] = $subtotal;
  541. $this->post['member_id'] = $this->post['custom'];
  542. $customer_email_template = $row->customer_email_template;
  543. $admin_email_template = $row->admin_email_template;
  544. $new_member_group = $row->new_member_group;
  545. // Type Specific Actions
  546. // we ignore subscr_cancel actions since they do not affect the current subscription
  547. if ($type == 'subscr_eot')
  548. {
  549. $new_member_group = $row->member_group_unsubscribe;
  550. $admin_email_template = $row->admin_email_template_unsubscribe;
  551. $customer_email_template = $row->customer_email_template_unsubscribe;
  552. if ($this->end_subscription() === FALSE)
  553. {
  554. return FALSE;
  555. }
  556. }
  557. elseif ($type == 'subscr_signup')
  558. {
  559. if ($this->start_subscription($row) === FALSE)
  560. {
  561. return FALSE;
  562. }
  563. }
  564. /* -------------------------------------
  565. /* 'simple_commerce_perform_actions_start' hook.
  566. /* - After a purchase is recorded, do more processing before EE's processing
  567. /* - Added EE 1.5.1
  568. */
  569. if ($this->EE->extensions->active_hook('simple_commerce_perform_actions_start') === TRUE)
  570. {
  571. $edata = $this->EE->extensions->universal_call('simple_commerce_perform_actions_start', $this, $query->row());
  572. if ($this->EE->extensions->end_script === TRUE) return;
  573. }
  574. /*
  575. /* -------------------------------------*/
  576. if ($type == '')
  577. {
  578. /* --------------------------------
  579. /* Check Price
  580. /* - There is a small chance the Admin changed the price between
  581. /* purchase and the receipt of the IP, so we give a small bit of
  582. /* wiggle room. About 10%...
  583. /* --------------------------------*/
  584. $price = ($row->item_use_sale == 'y') ? $row->item_sale_price : $row->item_regular_price;
  585. $cost = $subtotal/$qnty;
  586. if ($cost < ($price * 0.9))
  587. {
  588. return;
  589. }
  590. $data = array('txn_id' => $this->post['txn_id'],
  591. 'member_id' => $this->post['custom'],
  592. 'item_id' => $row->item_id,
  593. 'purchase_date' => $this->EE->localize->now,
  594. 'item_cost' => $cost,
  595. 'paypal_details' => serialize($this->post));
  596. if ( ! is_numeric($qnty) OR $qnty == 1)
  597. {
  598. $this->EE->db->insert('exp_simple_commerce_purchases', $data);
  599. $this->EE->db->where('item_id', $item_id);
  600. $this->EE->db->set('item_purchases', "item_purchases + 1", FALSE);
  601. $this->EE->db->update('exp_simple_commerce_items');
  602. }
  603. else
  604. {
  605. for($i=0; $i < $qnty; ++$i)
  606. {
  607. $this->EE->db->insert('exp_simple_commerce_purchases', $data);
  608. }
  609. $this->EE->db->where('item_id', $item_id);
  610. $this->EE->db->set('item_purchases', "item_purchases + {$qnty}", FALSE);
  611. $this->EE->db->update('exp_simple_commerce_items');
  612. }
  613. } // end non-sub entry
  614. // New Member Group
  615. if ($new_member_group != '' && $new_member_group != 0)
  616. {
  617. $this->EE->db->where('member_id', $this->post['custom']);
  618. $this->EE->db->where('group_id !=', 1);
  619. $this->EE->db->update('exp_members', array('group_id' => $new_member_group));
  620. }
  621. // Send Emails!
  622. $this->EE->load->library('email');
  623. if ($customer_email_template != '' && $customer_email_template != 0)
  624. {
  625. $this->EE->db->select('email');
  626. $result = $this->EE->db->get_where('exp_members', array('member_id' => $this->post['custom']));
  627. $cust_row = $result->row();
  628. $to = $cust_row->email;
  629. $this->EE->db->select('email_subject, email_body');
  630. $result = $this->EE->db->get_where('exp_simple_commerce_emails', array('email_id' => $customer_email_template));
  631. if ($result->num_rows() > 0)
  632. {
  633. $email = $result->row();
  634. $subject = $email->email_subject;
  635. $message = $email->email_body;
  636. foreach($this->post as $key => $value)
  637. {
  638. $subject = str_replace(LD.$key.RD, $value, $subject);
  639. $message = str_replace(LD.$key.RD, $value, $message);
  640. }
  641. // Load the text helper
  642. $this->EE->load->helper('text');
  643. $this->EE->email->from($this->EE->config->item('webmaster_email'),
  644. $this->EE->config->item('site_name'));
  645. $this->EE->email->to($to);
  646. $this->EE->email->subject($subject);
  647. $this->EE->email->message(entities_to_ascii($message));
  648. $this->EE->email->send();
  649. $this->EE->email->EE_initialize();
  650. }
  651. }
  652. if ($row->admin_email_address != '' && $admin_email_template != '' && $admin_email_template != 0)
  653. {
  654. $this->EE->db->select('email_subject, email_body');
  655. $result = $this->EE->db->get_where('exp_simple_commerce_emails', array('email_id' => $admin_email_template));
  656. if ($result->num_rows() > 0)
  657. {
  658. $email = $result->row();
  659. $subject = $email->email_subject;
  660. $message = $email->email_body;
  661. foreach($this->post as $key => $value)
  662. {
  663. $subject = str_replace(LD.$key.RD, $value, $subject);
  664. $message = str_replace(LD.$key.RD, $value, $message);
  665. }
  666. // Load the text helper
  667. $this->EE->load->helper('text');
  668. $this->EE->email->from($this->EE->config->item('webmaster_email'),
  669. $this->EE->config->item('site_name'));
  670. $this->EE->email->to($row->admin_email_address);
  671. $this->EE->email->subject($subject);
  672. $this->EE->email->message(entities_to_ascii($message));
  673. $this->EE->email->send();
  674. $this->EE->email->EE_initialize();
  675. }
  676. }
  677. /* -------------------------------------
  678. /* 'simple_commerce_perform_actions_end' hook.
  679. /* - After a purchase is recorded, do more processing
  680. /* - Added EE 1.5.1
  681. */
  682. if ($this->EE->extensions->active_hook('simple_commerce_perform_actions_end') === TRUE)
  683. {
  684. $edata = $this->EE->extensions->universal_call('simple_commerce_perform_actions_end', $this, $query->row());
  685. if ($this->EE->extensions->end_script === TRUE) return;
  686. }
  687. /*
  688. /* -------------------------------------*/
  689. }
  690. /** ----------------------------------------
  691. /** End Subscription for Item and USer
  692. /** ----------------------------------------*/
  693. function end_subscription()
  694. {
  695. // Check for Subscription
  696. $this->EE->db->select('purchase_id, item_id');
  697. $this->EE->db->where('member_id', $this->post['custom']);
  698. $this->EE->db->where('paypal_subscriber_id', $this->post['subscr_id']);
  699. $query = $this->EE->db->get('exp_simple_commerce_purchases');
  700. // what if multiple subscriptions? item_number viable??? -rob1
  701. // http://articles.techrepublic.com.com/5100-10878_11-5331883.html
  702. // k- 0 is still subscribed. If it has a date? They were unsubscribed then. So- null if not subscription type.
  703. if ($query->num_rows() == 0)
  704. {
  705. return FALSE;
  706. }
  707. $data = array('subscription_end_date' => $this->EE->localize->now);
  708. $this->EE->db->where('purchase_id', $query->row('purchase_id'));
  709. $this->EE->db->update('exp_simple_commerce_purchases', $data);
  710. $this->EE->db->where('item_id', $query->row('item_id'));
  711. $this->EE->db->set('current_subscriptions', "current_subscriptions - 1 ", FALSE);
  712. $this->EE->db->update('exp_simple_commerce_items');
  713. return TRUE;
  714. }
  715. /* END end_subscription() */
  716. /** ----------------------------------------
  717. /** Start Subscription for Item
  718. /** ----------------------------------------*/
  719. function start_subscription($row)
  720. {
  721. /* --------------------------------
  722. /* Check Price
  723. /* - There is a small chance the Admin changed the price between purchase and the receipt
  724. /* of the IP, so we give a small bit of wiggle room. About 10%...
  725. /* --------------------------------*/
  726. $price = ($row->item_use_sale == 'y') ? $row->item_sale_price : $row->item_regular_price;
  727. if ($this->post['mc_amount3'] < ($price * 0.9))
  728. {
  729. return FALSE;
  730. }
  731. /** --------------------------------------------
  732. /** Check Subscription!
  733. /** --------------------------------------------*/
  734. // period3: Regular subscription interval in days, weeks, months, or years (ex: a 4 day interval is "period3: 4 D")
  735. $period = $row->subscription_frequency.' '.strtoupper(substr($row->subscription_frequency_unit, 0, 1));
  736. if ( ! isset($this->post['period3']) OR trim($this->post['period3']) != $period)
  737. {
  738. return FALSE;
  739. }
  740. if ( ! isset($this->post['recurring']) OR $this->post['recurring'] != 1)
  741. {
  742. return FALSE;
  743. }
  744. // Insert Subscription
  745. $data = array('txn_id' => $this->post['txn_id'],
  746. 'member_id' => $this->post['custom'],
  747. 'item_id' => $row->item_id,
  748. 'purchase_date' => $this->EE->localize->now,
  749. 'item_cost' => $this->post['mc_amount3'],
  750. 'paypal_details' => serialize($this->post),
  751. 'paypal_subscriber_id' => $this->post['subscr_id']);
  752. $this->EE->db->insert('exp_simple_commerce_purchases', $data);
  753. $this->EE->db->where('item_id', $row->item_id);
  754. $this->EE->db->set('item_purchases', "item_purchases + 1", FALSE);
  755. $this->EE->db->set('current_subscriptions', "current_subscriptions + 1", FALSE);
  756. $this->EE->db->update('exp_simple_commerce_items');
  757. return TRUE;
  758. }
  759. /* END start_subscription() */
  760. /** ----------------------------------------
  761. /** Encrypt Button
  762. /** ----------------------------------------*/
  763. function encrypt_data($params = array(), $type='button')
  764. {
  765. /** -----------------------------
  766. /** Certificates, Keys, and TMP Files
  767. /** -----------------------------*/
  768. $public_certificate = file_get_contents($this->public_certificate);
  769. $private_key = file_get_contents($this->private_key);
  770. $paypal_certificate = file_get_contents($this->paypal_certificate);
  771. $tmpin_file = tempnam($this->temp_path, 'paypal_');
  772. $tmpout_file = tempnam($this->temp_path, 'paypal_');
  773. $tmpfinal_file = tempnam($this->temp_path, 'paypal_');
  774. /** -----------------------------
  775. /** Prepare Our Data
  776. /** -----------------------------*/
  777. $rawdata = '';
  778. $params['cert_id'] = $this->certificate_id;
  779. foreach ($params as $name => $value)
  780. {
  781. $rawdata .= "$name=$value\n";
  782. }
  783. if ( ! $fp = fopen($tmpin_file, 'w'))
  784. {
  785. exit('failure');
  786. }
  787. fwrite($fp, rtrim($rawdata));
  788. fclose($fp);
  789. /** -----------------------------
  790. /** Sign Our File
  791. /** -----------------------------*/
  792. if ( ! openssl_pkcs7_sign($tmpin_file, $tmpout_file, $public_certificate, $private_key, array(), PKCS7_BINARY))
  793. {
  794. exit("Could not sign encrypted data: " . openssl_error_string());
  795. }
  796. $data = explode("\n\n", file_get_contents($tmpout_file));
  797. $data = base64_decode($data['1']);
  798. if ( ! $fp = fopen($tmpout_file, 'w'))
  799. {
  800. exit("Could not open temporary file '$tmpin_file')");
  801. }
  802. fwrite($fp, $data);
  803. fclose($fp);
  804. /** -----------------------------
  805. /** Encrypt Our Data
  806. /** -----------------------------*/
  807. if ( ! openssl_pkcs7_encrypt($tmpout_file, $tmpfinal_file, $paypal_certificate, array(), PKCS7_BINARY))
  808. {
  809. exit("Could not encrypt data:" . openssl_error_string());
  810. }
  811. $encdata = file_get_contents($tmpfinal_file, FALSE);
  812. if (empty($encdata))
  813. {
  814. exit("Encryption and signature of data failed.");
  815. }
  816. $encdata = explode("\n\n", $encdata);
  817. $encdata = trim(str_replace("\n", '', $encdata['1']));
  818. $encdata = "-----BEGIN PKCS7-----".$encdata."-----END PKCS7-----";
  819. @unlink($tmpfinal_file);
  820. @unlink($tmpin_file);
  821. @unlink($tmpout_file);
  822. /** -----------------------------
  823. /** Return The Encrypted Data String
  824. /** -----------------------------*/
  825. return $encdata;
  826. }
  827. /** -------------------------------------
  828. /** Clean the values for use in URLs
  829. /** -------------------------------------*/
  830. function prep_val($str)
  831. {
  832. // Oh, PayPal, the hoops I must jump through to woo thee...
  833. // PayPal is displaying its cart as UTF-8, sending UTF-8 headers, but when
  834. // processing the form data, is obviously wonking with it. This will force
  835. // accented characters in item names to display properly on the shopping cart
  836. // but alas only for unencrypted data. PayPal won't accept this same
  837. // workaround for encrypted form data.
  838. // Load the typography helper so we can do entity_decode()
  839. $this->EE->load->helper('typography');
  840. $str = str_replace('&amp;', '&', $str);
  841. $str = urlencode(utf8_decode(entity_decode($str, 'utf-8')));
  842. return $str;
  843. }
  844. }
  845. /* End of file mod.simple_commerce.php */
  846. /* Location: ./system/expressionengine/modules/simple_commerce/mod.simple_commerce.php */