Payfort.php 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. <?php
  2. namespace Payment\Lib;
  3. use Dever;
  4. class Payfort extends Core
  5. {
  6. private $config = array();
  7. private $language = 'en';
  8. private $url = 'https://checkout.payfort.com/FortAPI/paymentPage';
  9. private $gatewayUrl = 'https://paymentservices.payfort.com/FortAPI/paymentApi';
  10. public function __construct($name, $config)
  11. {
  12. $this->name = $name;
  13. $this->config = $config;
  14. }
  15. private function getType($type, $currency = '')
  16. {
  17. if ($type < 5 && $currency == 'SAR') {
  18. $type = 4;
  19. }
  20. $name = $value = $method = $command = '';
  21. switch ($type) {
  22. case 1:
  23. # 目前不支持
  24. $name = 'Pay with credit cards (Redirection)';
  25. $method = 'redirection';
  26. $currency = '';
  27. $command = 'PURCHASE';
  28. break;
  29. case 2:
  30. $name = 'Pay with installments (Redirection)';
  31. $method = 'redirection';
  32. $currency = 'USD';
  33. $command = 'PURCHASE';
  34. break;
  35. case 3:
  36. $name = 'Pay with NAPS';
  37. $value = 'NAPS';
  38. $currency = 'NAPS';
  39. $command = 'AUTHORIZATION';
  40. $method = 'redirection';
  41. break;
  42. case 4:
  43. $name = 'Pay with SADAD';
  44. $value = 'SADAD';
  45. $currency = 'SAR';
  46. $method = 'redirection';
  47. $command = 'AUTHORIZATION';
  48. break;
  49. case 11:
  50. $name = 'Pay with credit cards (Merchant Page)';
  51. $method = 'page';
  52. $currency = '';
  53. $command = 'TOKENIZATION';
  54. break;
  55. case 12:
  56. $name = 'Pay with installments (Merchant Page)';
  57. $method = 'page';
  58. $currency = '';
  59. $command = 'TOKENIZATION';
  60. break;
  61. case 21:
  62. $name = 'Pay with credit cards (Merchant Page 2.0)';
  63. $method = 'page_v2';
  64. $currency = '';
  65. $command = 'TOKENIZATION';
  66. break;
  67. }
  68. $currency = strtoupper($currency);
  69. return array
  70. (
  71. 'id' => $type,
  72. 'name' => $name,
  73. 'value' => $value,
  74. 'method' => $method,
  75. 'currency' => $currency,
  76. 'command' => $command,
  77. );
  78. }
  79. /**
  80. * 获取统一下单的基本信息
  81. */
  82. public function request($type, $uid, $account, $product_name, $amount, $currency, $data = array())
  83. {
  84. if (!$data) {
  85. $data = array();
  86. }
  87. $type = $this->getType($type, $currency);
  88. $order_id = $this->createOrder($uid, $this->name, $product_name, $amount, $type['currency'], $type['id'], $type['name']);
  89. $method = $type['method'];
  90. $param = array();
  91. if ($type['id'] == 3) {
  92. $param['order_description'] = $product_name;
  93. }
  94. $param = $this->param($order_id, $amount, $type['currency'], $type['command'], $type['value'], $type['id'], $param);
  95. $data += $param;
  96. return $this->result($method, $param, $data);
  97. }
  98. /**
  99. * 生成基本参数
  100. *
  101. * @return mixed
  102. */
  103. private function param($order_id, $amount, $currency, $command, $payment_option, $type, $param = array())
  104. {
  105. if ($type == 2 || $type == 12) {
  106. $param['installments'] = 'STANDALONE';
  107. }
  108. if ($type == 12 && isset($param['plan_code'])) {
  109. $param['installments'] = 'YES';
  110. $command = 'PURCHASE';
  111. }
  112. if ($currency) {
  113. $param['amount'] = $this->convertFortAmount($amount, $currency);
  114. $param['currency'] = $currency;
  115. }
  116. $param['access_code'] = $this->config['access_code'];
  117. $param['merchant_identifier'] = $this->config['merchant_id'];
  118. $param['merchant_reference'] = $order_id;
  119. $param['language'] = $this->language;
  120. if ($payment_option) {
  121. $param['payment_option'] = $payment_option;
  122. }
  123. # AUTHORIZATION(授权)、PURCHASE(购买) TOKENIZATION CHECK_STATUS
  124. if ($command == 'TOKENIZATION') {
  125. $param['service_command'] = $command;
  126. } else {
  127. $param['command'] = $command;
  128. }
  129. $param['return_url'] = Dever::url('api.notify?order_id=' . $order_id, 'payment');
  130. $param['signature'] = $this->signature($this->config['request_phrase'], $param);
  131. return $param;
  132. }
  133. /**
  134. * 获取返回数据
  135. *
  136. * @return mixed
  137. */
  138. private function result($method, $param, $data)
  139. {
  140. $form = $this->form($param);
  141. return array('form' => $form, 'url' => $this->url, 'param' => $data, 'method' => $method);
  142. }
  143. /**
  144. * 通知回调
  145. *
  146. * @return mixed
  147. */
  148. public function notify($param)
  149. {
  150. if (empty($param)) {
  151. return $this->out('invalid_parameters');
  152. }
  153. if (!isset($param['signature'])) {
  154. return $this->out('invalid_parameters');
  155. }
  156. $post = $param;
  157. $responseSignature = $param['signature'];
  158. $order_id = $param['merchant_reference'];
  159. unset($param['l']);
  160. if (isset($param['3ds'])) {
  161. unset($param['3ds']);
  162. }
  163. if (isset($param['product_name'])) {
  164. unset($param['product_name']);
  165. }
  166. if (isset($param['integration_type'])) {
  167. unset($param['integration_type']);
  168. }
  169. if (isset($param['signature'])) {
  170. unset($param['signature']);
  171. }
  172. if (isset($param['order_id'])) {
  173. unset($param['order_id']);
  174. }
  175. if (isset($param['type'])) {
  176. unset($param['type']);
  177. }
  178. if (isset($param['currency']) && $param['currency']) {
  179. $param['amount'] = $this->convertFortAmount($param['amount'], $param['currency']);
  180. }
  181. $amount = $param['amount'];
  182. if (isset($param['card_number']) && $param['card_number']) {
  183. unset($param['amount']);
  184. }
  185. $signature = $this->signature($this->config['response_phrase'], $param);
  186. if ($signature != $responseSignature) {
  187. return $this->updateOrder($param['merchant_reference'], $amount, 'invalid_signature');
  188. }
  189. if (substr($param['response_code'], 2) != '000') {
  190. return $this->updateOrder($param['merchant_reference'], $amount, $param['response_message']);
  191. }
  192. if (isset($param['card_number']) && $param['card_number']) {
  193. return $this->pageNotify($post);
  194. }
  195. return $this->out('ok');
  196. }
  197. /**
  198. * merchantPageNotifyFort
  199. *
  200. * @return mixed
  201. */
  202. private function pageNotify($param)
  203. {
  204. $type = $this->getType($param['type']);
  205. $method = $type['method'];
  206. $post = array();
  207. $post['customer_ip'] = $_SERVER['REMOTE_ADDR'];
  208. if (isset($param['token_name'])) {
  209. $post['token_name'] = $param['token_name'];
  210. }
  211. if(isset($param['3ds']) && $param['3ds'] == 'no') {
  212. $post['check_3ds'] = 'NO';
  213. }
  214. if (!$type['currency']) {
  215. $type['currency'] = 'USD';
  216. }
  217. $type['command'] = 'AUTHORIZATION';
  218. $post = $this->param($param['order_id'], $param['amount'], $type['currency'], $type['command'], $type['value'], $type['id'], $post);
  219. print_r($post);die;
  220. $result = Dever::curl($this->gatewayUrl, $post, 'post');
  221. return $this->notify($result);
  222. }
  223. public function form($data)
  224. {
  225. $form = '<form style="display:none" name="sg-form" id="sg-form" method="post" action="' . $this->url . '">';
  226. foreach ($data as $k => $v) {
  227. $form .= '<input type="hidden" name="' . $k . '" value="' . $v . '">';
  228. }
  229. $form .= '<input type="submit" id="submit">';
  230. return $form;
  231. }
  232. /**
  233. * signature
  234. *
  235. * @return mixed
  236. */
  237. private function signature($phrase, $request)
  238. {
  239. ksort($request);
  240. $signature_string = '';
  241. foreach ($request as $k => $v) {
  242. $signature_string .= $k . '=' . $v;
  243. }
  244. $signature_string = $phrase . $signature_string . $phrase;
  245. return hash('sha256', $signature_string);
  246. }
  247. /**
  248. * Convert Amount with dicemal points
  249. * @param decimal $amount
  250. * @param string $currencyCode
  251. * @return decimal
  252. */
  253. private function convertFortAmount($amount, $currencyCode)
  254. {
  255. $new_amount = 0;
  256. $total = $amount;
  257. $decimalPoints = $this->getCurrencyDecimalPoints($currencyCode);
  258. $new_amount = round($total, $decimalPoints) * (pow(10, $decimalPoints));
  259. return $new_amount;
  260. }
  261. private function castAmountFromFort($amount, $currencyCode)
  262. {
  263. $decimalPoints = $this->getCurrencyDecimalPoints($currencyCode);
  264. //return $amount / (pow(10, $decimalPoints));
  265. $new_amount = round($amount, $decimalPoints) / (pow(10, $decimalPoints));
  266. return $new_amount;
  267. }
  268. private function getCurrencyDecimalPoints($currency)
  269. {
  270. $decimalPoint = 2;
  271. $arrCurrencies = array(
  272. 'JOD' => 3,
  273. 'KWD' => 3,
  274. 'OMR' => 3,
  275. 'TND' => 3,
  276. 'BHD' => 3,
  277. 'LYD' => 3,
  278. 'IQD' => 3,
  279. 'USD' => 0,
  280. );
  281. if (isset($arrCurrencies[$currency])) {
  282. $decimalPoint = $arrCurrencies[$currency];
  283. }
  284. return $decimalPoint;
  285. }
  286. }