PageRenderTime 22ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/View/Helper/PaypalHelper.php

http://github.com/webtechnick/CakePHP-Paypal-IPN-Plugin
PHP | 337 lines | 214 code | 30 blank | 93 comment | 37 complexity | efa095f1465c66b2c6b5a15dd21ef687 MD5 | raw file
  1. <?php
  2. /**
  3. * Paypal Helper part of the PayPal IPN plugin.
  4. *
  5. * @author Nick Baker
  6. * @link http://www.webtechnick.com
  7. * @license MIT
  8. */
  9. App::uses('AppHelper','View/Helper');
  10. class PaypalHelper extends AppHelper {
  11. var $helpers = array('Html', 'Form');
  12. var $config = array();
  13. var $encryption = array();
  14. /**
  15. * Setup the config based on either the Configure::read('debug') values
  16. * or the PaypalIpnConfig in config/paypal_ipn_config.php
  17. *
  18. * Will attempt to read configuration in the following order:
  19. * Configure::read('PaypalIpn')
  20. * App::import() of config/paypal_ipn_config.php
  21. * App::import() of plugin's config/paypal_ipn_config.php
  22. */
  23. function __construct(View $View, $settings = array()) {
  24. $this->config = Configure::read('PaypalIpn');
  25. if (empty($this->config)) {
  26. $importConfig = array(
  27. 'type' => 'File',
  28. 'name' => 'PaypalIpn.PaypalIpnConfig',
  29. 'file' => APP . 'Config' . DS . 'paypal_ipn_config.php'
  30. );
  31. if (!class_exists('PaypalIpnConfig')) {
  32. App::import($importConfig);
  33. }
  34. if (!class_exists('PaypalIpnConfig')) {
  35. // Import from paypal plugin configuration
  36. $importConfig['file'] = 'Config' . DS . 'paypal_ipn_config.php';
  37. App::import($importConfig);
  38. }
  39. if (!class_exists('PaypalIpnConfig')) {
  40. trigger_error(__d('paypal_ipn', 'PaypalIpnConfig: The configuration could not be loaded.'), E_USER_ERROR);
  41. }
  42. $config = new PaypalIpnConfig();
  43. $vars = get_object_vars($config);
  44. foreach ($vars as $property => $configuration) {
  45. if (strpos($property, 'encryption_') === 0) {
  46. $name = substr($property, 11);
  47. $this->encryption[$name] = $configuration;
  48. } else {
  49. $this->config[$property] = $configuration;
  50. }
  51. }
  52. }
  53. parent::__construct($View, $settings);
  54. }
  55. /**
  56. * Creates a complete form button to Pay Now, Donate,
  57. * Add to Cart, or Subscribe using the paypal service.
  58. * Configuration for the button is in /config/paypal_ip_config.php
  59. *
  60. * for this to work the option 'item_name' and 'amount' must be set in the array options or default config options.
  61. *
  62. * Example:
  63. * $paypal->button('Pay Now', array('amount' => '12.00', 'item_name' => 'test item'));
  64. * $paypal->button('Subscribe', array('type' => 'subscribe', 'amount' => '60.00', 'term' => 'month', 'period' => '2'));
  65. * $paypal->button('Donate', array('type' => 'donate', 'amount' => '60.00'));
  66. * $paypal->button('Add To Cart', array('type' => 'addtocart', 'amount' => '15.00'));
  67. * $paypal->button('View Cart', array('type' => 'viewcart'));
  68. * $paypal->button('Unsubscribe', array('type' => 'unsubscribe'));
  69. * $paypal->button('Checkout', array(
  70. * 'type' => 'cart',
  71. * 'items' => array(
  72. * array('item_name' => 'Item 1', 'amount' => '120', 'quantity' => 2, 'item_number' => '1234'),
  73. * array('item_name' => 'Item 2', 'amount' => '50'),
  74. * array('item_name' => 'Item 3', 'amount' => '80', 'quantity' => 3),
  75. * )
  76. * ));
  77. *
  78. * Test Example:
  79. * $paypal->button('Pay Now', array('test' => true, 'amount' => '12.00', 'item_name' => 'test item'));
  80. *
  81. * @access public
  82. * @param String $title takes the title of the paypal button (default "Pay Now" or "Subscribe" depending on option['type'])
  83. * @param Array $options takes an options array defaults to (configuration in /config/paypal_ipn_config.php)
  84. * test: true|false switches default settings in /config/paypal_ipn_config.php between settings and testSettings
  85. * type: 'paynow', 'addtocart', 'donate', 'unsubscribe', 'cart', or 'subscribe' (default 'paynow')
  86. *
  87. * You may pass in api name value pairs to be passed directly to the paypal
  88. * form link. Refer to paypal.com for a complete list. Some Paypal API examples:
  89. * float amount - value
  90. * string notify_url - url
  91. * string item_name - name of product.
  92. */
  93. function button($title, $options = array(), $buttonOptions = array()) {
  94. if (is_array($title)) {
  95. $buttonOptions = $options;
  96. $options = $title;
  97. } else if (empty($buttonOptions['label'])) {
  98. $buttonOptions['label'] = $title;
  99. }
  100. $encryption = false;
  101. if (!empty($options['test'])) {
  102. if ($options['test'] === true) {
  103. $defaults = $this->config['test'];
  104. $encryption = 'test';
  105. } elseif (is_array($options['test'])) {
  106. $defaults = $options['test'];
  107. if (isset($options['_encryption'])) {
  108. $encryption = $options['_encryption'];
  109. unset($options['_encryption']);
  110. }
  111. } else {
  112. $defaults = $this->config[$options['test']];
  113. $encryption = $options['test'];
  114. }
  115. } else {
  116. $defaults = $this->config['default'];
  117. $encryption = 'default';
  118. }
  119. $options = array_merge($defaults, $options);
  120. $options['type'] = (isset($options['type'])) ? $options['type'] : "paynow";
  121. switch ($options['type']) {
  122. case 'subscribe': // Subscribe
  123. $options['cmd'] = '_xclick-subscriptions';
  124. $default_title = 'Subscribe';
  125. $options['no_note'] = 1;
  126. $options['no_shipping'] = 1;
  127. $options['src'] = 1;
  128. $options['sra'] = 1;
  129. $options = $this->__subscriptionOptions($options);
  130. break;
  131. case 'addtocart': // Add To Cart
  132. $options['cmd'] = '_cart';
  133. $options['add'] = '1';
  134. $default_title = 'Add To Cart';
  135. break;
  136. case 'viewcart': // View Cart
  137. $options['cmd'] = '_cart';
  138. $options['display'] = '1';
  139. $default_title = 'View Cart';
  140. break;
  141. case 'donate': // Doante
  142. $options['cmd'] = '_donations';
  143. $default_title = 'Donate';
  144. break;
  145. case 'unsubscribe': //Unsubscribe
  146. $options['cmd'] = '_subscr-find';
  147. $options['alias'] = $options['business'];
  148. $default_title = 'Unsubscribe';
  149. break;
  150. case 'cart': // upload cart
  151. $options['cmd'] = '_cart';
  152. $options['upload'] = 1;
  153. $default_title = 'Checkout';
  154. $options = $this->__uploadCartOptions($options);
  155. break;
  156. default: // Pay Now
  157. $options['cmd'] = '_xclick';
  158. $default_title = 'Pay Now';
  159. break;
  160. }
  161. if (empty($buttonOptions['label'])) {
  162. if (empty($options['label'])) {
  163. $buttonOptions['label'] = $default_title;
  164. } else {
  165. $buttonOptions['label'] = $options['label'];
  166. }
  167. }
  168. $retval = "<form action='{$options['server']}/cgi-bin/webscr' method='post'><div class='paypal-form'>";
  169. unset($options['server']);
  170. $encryptedFields = false;
  171. if (!empty($options['encrypt']) && $encryption) {
  172. if (is_string($encryption) && isset($this->encryption[$encryption])) {
  173. $encryption = $this->encryption[$encryption];
  174. }
  175. if (is_array($encryption)) {
  176. $encryptedFields = $this->__encryptFields($options, $encryption);
  177. }
  178. }
  179. if ($encryptedFields === false) {
  180. foreach ($options as $name => $value) {
  181. $retval .= $this->__hiddenNameValue($name, $value);
  182. }
  183. } else {
  184. $retval .= $encryptedFields;
  185. }
  186. $retval .= $this->__submitButton($buttonOptions);
  187. return $retval;
  188. }
  189. /**
  190. * Constructs the name value pair in a hidden input html tag
  191. *
  192. * @param array hold key/value options of paypal button.
  193. * @return String hidden encrypted fields
  194. */
  195. function __encryptFields($options, $encryption) {
  196. if (!file_exists($encryption['key_file'])) {
  197. $this->log("ERROR: MY_KEY_FILE {$encryption['key_file']} not found\n");
  198. return false;
  199. }
  200. if (!file_exists($encryption['cert_file'])) {
  201. $this->log("ERROR: MY_CERT_FILE {$encryption['cert_file']} not found\n");
  202. return false;
  203. }
  204. if (!file_exists($encryption['paypal_cert_file'])) {
  205. $this->log("ERROR: PAYPAL_CERT_FILE {$encryption['paypal_cert_file']} not found\n");
  206. return false;
  207. }
  208. $options['cert_id'] = $encryption['cert_id'];
  209. // Assign Build Notation for PayPal Support
  210. $options['bn'] = $encryption['bn'];
  211. $data = '';
  212. foreach ($options as $key => $value) {
  213. if ($value != '') {
  214. $data .= "{$key}={$value}\n";
  215. }
  216. }
  217. $openssl_cmd = array();
  218. $openssl_cmd[] = "({$encryption['openssl']} smime";
  219. $openssl_cmd[] = "-sign -signer {$encryption['cert_file']}";
  220. $openssl_cmd[] = "-inkey {$encryption['key_file']}";
  221. $openssl_cmd[] = "-outform der -nodetach -binary <<_EOF_\n{$data}\n_EOF_\n) |";
  222. $openssl_cmd[] = "{$encryption['openssl']} smime -encrypt";
  223. $openssl_cmd[] = "-des3 -binary -outform pem {$encryption['paypal_cert_file']}";
  224. $openssl_cmd = implode(' ', $openssl_cmd);
  225. exec($openssl_cmd, $output, $error);
  226. if ($error) {
  227. return false;
  228. }
  229. $encryptedFields = implode("\n", $output);
  230. return implode(' ', array(
  231. '<input type="hidden" name="cmd" value="_s-xclick">',
  232. "<input type='hidden' name='encrypted' value='{$encryptedFields}' />"
  233. ));
  234. }
  235. /**
  236. * Constructs the name value pair in a hidden input html tag
  237. *
  238. * @param string name is the name of the hidden html element.
  239. * @param string value is the value of the hidden html element.
  240. * @return string hidden html field
  241. */
  242. function __hiddenNameValue($name, $value){
  243. return "<input type='hidden' name='{$name}' value='{$value}' />";
  244. }
  245. /**
  246. * Constructs the submit button from the provided text
  247. *
  248. * @param string text | text is the label of the submit button. Can use plain text or image url.
  249. * @return string html form button and close form
  250. */
  251. function __submitButton($options = array()) {
  252. $options = is_array($options) ? $options : array('label' => $options);
  253. return "</div>" . $this->Form->end($options);
  254. }
  255. /**
  256. * Converts human readable subscription terms into paypal terms if need be
  257. *
  258. * @param array options | human readable options into paypal API options
  259. * int period - paypal api period of term, 2, 3, 1
  260. * string term - paypal API term //month, year, day, week
  261. * float amount - paypal API amount to charge for perioud of term.
  262. * @return array options
  263. */
  264. function __subscriptionOptions($options = array()) {
  265. // Period... every 1, 2, 3, etc.. Term
  266. if (isset($options['period'])) {
  267. $options['p3'] = $options['period'];
  268. unset($options['period']);
  269. }
  270. // Mount billed
  271. if (isset($options['amount'])) {
  272. $options['a3'] = $options['amount'];
  273. unset($options['amount']);
  274. }
  275. // Terms, Month(s), Day(s), Week(s), Year(s)
  276. if (isset($options['term'])) {
  277. switch ($options['term']) {
  278. case 'month': $options['t3'] = 'M'; break;
  279. case 'year': $options['t3'] = 'Y'; break;
  280. case 'day': $options['t3'] = 'D'; break;
  281. case 'week': $options['t3'] = 'W'; break;
  282. default: $options['t3'] = $options['term'];
  283. }
  284. unset($options['term']);
  285. }
  286. return $options;
  287. }
  288. /**
  289. * Converts an array of items into paypal friendly name/value pairs
  290. *
  291. * @param array of options that will be returned with proper paypal friendly name/value pairs for items
  292. * @return array options
  293. */
  294. function __uploadCartOptions($options = array()) {
  295. if (isset($options['items']) && is_array($options['items'])) {
  296. $count = 1;
  297. foreach ($options['items'] as $item) {
  298. foreach ($item as $key => $value) {
  299. $options[$key.'_'.$count] = $value;
  300. }
  301. $count++;
  302. }
  303. unset($options['items']);
  304. }
  305. return $options;
  306. }
  307. }