Account.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. <?php namespace Pay\Yspay;
  2. use Dever;
  3. /**
  4. * 银联商务代付
  5. * Class Chinaums
  6. */
  7. class Account
  8. {
  9. //测试地址
  10. protected $test_host = 'https://mobl-test.chinaums.com/';
  11. //正式地址
  12. protected $host = 'https://managefree.chinaums.com/';
  13. //系统编号(sysId)
  14. protected $sys_id = '10119';
  15. //商户号
  16. protected $mch_id = '89810007372106N';
  17. //外部平台私钥
  18. protected $private_key = 'MIIEowIBAAKCAQEApzpOtvWGclmdw+/aEzAxwyTgUwnC9qjQEhL+qfMWDBIbFR8N4q6GQ8fRKZ9Zyvm0voFhgpH44Y6sh2U7rF9HQOuw2puywvU8kk5JAUxpxykbH7QqW/ijH1gBG3Ck/Ip/5I4co+q9K/CjQRmId5nSJ8ffnaiAOogNZycrP+AgEEU8vL1eNtnagVxT3EC1LEh0wBwecT9Tkyi0tMD0sMeIUl9POrnh7YADJtUzGf+TTNrqK6DhoT9mE3Plw0pqxKSk4/tHNx1ZIXf4I/UeYSEAreXHWVfLQ/if1C9HRYhEGB57mmqn0JdmsSRD7DX7eU7Oja+RqtWfQ/KH+2fnjq9uSwIDAQABAoIBABACUvrM8nwL/EB/u77OhFUMOLV6X8HBU3oHe33Fmby6FwGkoW2sC4p9nJaBfNUjppv+Qtl/I/Zj9DxaAqZz0Jx0c8/Zy/lCBPR0riSDrjS0yLX2R3/ag7NCd4iq9gB/OdMlj7RZipakSNy4lwnsHeRVDCFJukzgLXhMlaVdzXQBJTdERP3G8A9vwxuvbOE3q3kHCTWepVYd3KdEQ5rDPrYh/HwfVB2tWSne7Z/NurutW5qLA6aiJGcDoF7H41Fit8zw1QDnwJNvsUeR/POFFD0zog7+ZpMX3OiJwFKBZfTNvzJtH3mkqnN62JJwpJNqTTMWdfSziFlQNJ6GrCqhaxECgYEA1STJz0GAC7tho/l6O13BYlnyjS15bSCrr23XXUY3Sa7s6JiNFAUkIFq57XzEEdZhqOmgQlJQmGKJmmRVSshnSH7HohRdjisnjAbK1O0qABe3tP3IIuKCrPY+q1zb+PpYkFMiWUr3+1JYKU8o5tQCWQhRLVPN8Gbl6K0ffr3sJzcCgYEAyNoS4oWNeKnAJyK7rkDq7iMkf4eDMEUl1VPunZOTsZDkycf3bIKJJK+KW/HNpCt5M+DdhgZPtbuvpPVZFsscbM/q2q4vIBxp2riS94o+Aoijc8U5FzkhE+a5+qTJpykMBOVXaHENVvZzeh9TysoRROiI3c4IibKsP2NdwxnRU40CgYACozjoGqxl+MSljdHIaEmbWPeabaSiCBR30Eko+1R10fdWjYS5abLfv5+rY67ddaSxvWphR7l9mUKQqYswqLg2enMn+06JEtmjbvYVmnW5mJGKaNWQMPNjBo0R+80xEJAGATFcn4PgFU3H/RXJfXgl9+dhQzc6MVvI/FN2cw04EwKBgQCp3uaB9vpDxy3g65tYMUeAyPAhe/cUaCcrWaVCWIJdd3JIxnsYpv5erKiUQtnts2b63X/9znCz/1z6YxdKE9aioOa8tPzeZ6mPdvO1sJHpiq7TR0aVwZecQVOiDKUQX8LukRlwF810c1QPQVeY93XLle/LyGmoLBlKMzwlujw0MQKBgDZT/egpnQM3x4TR9ERrk0o5GOLHNFiNkSfkzzZ3D2nRGT+6GRlmb40LtPzBy5+vAgLqBlfEEfToaMGZ+Vrl2CePBBoR/j/q8nlziqZ3H5b8plqHSbX85zONT6tF+YZ2nRMxpI2gQtecRzoozm+ilELCNSd6V7pAzpl14KRU2V5l';
  19. //外部平台PKCS1私钥(银联商务提供的PKCS8格式需转为PKCS1格式)
  20. protected $private_key_pkcs1 = 'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCnOk629YZyWZ3D79oTMDHDJOBTCcL2qNASEv6p8xYMEhsVHw3iroZDx9Epn1nK+bS+gWGCkfjhjqyHZTusX0dA67Dam7LC9TySTkkBTGnHKRsftCpb+KMfWAEbcKT8in/kjhyj6r0r8KNBGYh3mdInx9+dqIA6iA1nJys/4CAQRTy8vV422dqBXFPcQLUsSHTAHB5xP1OTKLS0wPSwx4hSX086ueHtgAMm1TMZ/5NM2uoroOGhP2YTc+XDSmrEpKTj+0c3HVkhd/gj9R5hIQCt5cdZV8tD+J/UL0dFiEQYHnuaaqfQl2axJEPsNft5Ts6Nr5Gq1Z9D8of7Z+eOr25LAgMBAAECggEAEAJS+szyfAv8QH+7vs6EVQw4tXpfwcFTegd7fcWZvLoXAaShbawLin2cloF81SOmm/5C2X8j9mP0PFoCpnPQnHRzz9nL+UIE9HSuJIOuNLTItfZHf9qDs0J3iKr2AH850yWPtFmKlqRI3LiXCewd5FUMIUm6TOAteEyVpV3NdAElN0RE/cbwD2/DG69s4TereQcJNZ6lVh3cp0RDmsM+tiH8fB9UHa1ZKd7tn826u61bmosDpqIkZwOgXsfjUWK3zPDVAOfAk2+xR5H884UUPTOiDv5mkxfc6InAUoFl9M2/Mm0feaSqc3rYknCkk2pNMxZ19LOIWVA0noasKqFrEQKBgQDVJMnPQYALu2Gj+Xo7XcFiWfKNLXltIKuvbdddRjdJruzomI0UBSQgWrntfMQR1mGo6aBCUlCYYomaZFVKyGdIfseiFF2OKyeMBsrU7SoAF7e0/cgi4oKs9j6rXNv4+liQUyJZSvf7UlgpTyjm1AJZCFEtU83wZuXorR9+vewnNwKBgQDI2hLihY14qcAnIruuQOruIyR/h4MwRSXVU+6dk5OxkOTJx/dsgokkr4pb8c2kK3kz4N2GBk+1u6+k9VkWyxxsz+rari8gHGnauJL3ij4CiKNzxTkXOSET5rn6pMmnKQwE5VdocQ1W9nN6H1PKyhFE6IjdzgiJsqw/Y13DGdFTjQKBgAKjOOgarGX4xKWN0choSZtY95ptpKIIFHfQSSj7VHXR91aNhLlpst+/n6tjrt11pLG9amFHuX2ZQpCpizCouDZ6cyf7TokS2aNu9hWadbmYkYpo1ZAw82MGjRH7zTEQkAYBMVyfg+AVTcf9Fcl9eCX352FDNzoxW8j8U3ZzDTgTAoGBAKne5oH2+kPHLeDrm1gxR4DI8CF79xRoJytZpUJYgl13ckjGexim/l6sqJRC2e2zZvrdf/3OcLP/XPpjF0oT1qKg5ry0/N5nqY9287WwkemKrtNHRpXBl5xBU6IMpRBfwu6RGXAXzXRzVA9BV5j3dcuV78vIaagsGUozPCW6PDQxAoGANlP96CmdAzfHhNH0RGuTSjkY4sc0WI2RJ+TPNncPadEZP7oZGWZvjQu0/MHLn68CAuoGV8QR9OhowZn5WuXYJ48EGhH+P+ryeXOKpncflvymWodJtfznM41Pq0X5hnadEzGkjaBC15xHOijOb6KUQsI1J3pXukDOmXXgpFTZXmU=';
  21. //银商系统公钥
  22. protected $public_key = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhTzN8wxdXYr+/+t8iX0mlol8wFy+0pGtxnyB6PjyrIRjGHrZJA7grZPvy7MOK6PqihqTZh6SO7tX9StxVmTQo+PuibAY/p2i08UxkIBUcucHVvHN8gkM3GBFBqD0uJgUc03cerEI7gNeaKYfCVs0/hMo6CKbdXVKqaE987kXYK209uFcte+Y8YofQ2AYamImpzSf7pXomAu+8D98HIOs5bKITHTk30vPdNhrQdpDRO1TuX0x8bwhCykcwAEdB/Z9YGXkLU5S3QJY2qvCZJY08YdNqIpbDqifSRvOg0sqeKFXPfI2M0GsOh6PArTEmh0QHxDht9xjPPt11aVgh8kgkQIDAQAB';
  23. private function host()
  24. {
  25. return $this->host;
  26. }
  27. public function notify_api()
  28. {
  29. $msg = Dever::input();
  30. Dever::log($msg, 'yspay');
  31. $order = $msg['order'];
  32. if (!$order) {
  33. echo 'FAILED';die;
  34. }
  35. if (strstr($order, 'TX')) {
  36. $log = Dever::db('pay/yspay_tixian_log')->one(array('order_num' => $order));
  37. if ($log) {
  38. Dever::db('pay/yspay_tixian_log')->update(array('where_id' => $log['id'], 'status' => 2, 'response' => Dever::json_encode($msg)));
  39. $account = Dever::db('pay/yspay_merchant')->one($log['merchant_id']);
  40. if ($account) {
  41. Dever::db('pay/yspay_merchant')->dec(array('where_id' => $account['id'], 'set_yue' => $log['cash']));
  42. }
  43. }
  44. echo 'SUCCESS';die;
  45. }
  46. $where['order_num'] = $order;
  47. $order = Dever::db('yspay/sell_order')->find($where);
  48. $class = new Chinaums();
  49. if ($order && $order['withdraw'] == 1) {
  50. $content = $msg['content'];
  51. $content = $class->privateDecrypt($content);
  52. $log = Dever::db('pay/yspay_tixian_log')->one(array('order_num' => $order, 'shop_id' => $order['shop_id']));
  53. if ($content && isset($content['responseCode']) && ($content['responseCode'] == '000000' || $content['responseCode'] == '000001')) {
  54. Dever::db('shop/sell_order')->update(array('where_id' => $order['id'], 'withdraw' => 2));
  55. if ($log) {
  56. Dever::db('pay/yspay_tixian_log')->update(array('where_id' => $log['id'], 'status' => 2, 'response' => Dever::json_encode($content)));
  57. $account = Dever::db('shop/yspay_account')->one(array('shop_id' => $log['shop_id']));
  58. if ($account) {
  59. Dever::db('pay/yspay_account')->dec(array('where_id' => $account['id'], 'set_cash' => $log['cash']));
  60. }
  61. }
  62. echo 'SUCCESS';die;
  63. } else {
  64. Dever::load('shop/lib/cron')->yspayOne($order);
  65. }
  66. }
  67. echo 'FAILED';die;
  68. }
  69. public function shop_host($type,$content=false)
  70. {
  71. if ($type == 1) {
  72. return $this->host;
  73. } elseif($type == 2){
  74. return $this->mch_id;
  75. } elseif($type == 3){
  76. return $this->sys_id;
  77. } elseif($type == 4 && $content){
  78. return $this->createSignature($content);
  79. } elseif($type == 5 && $content){
  80. return $this->privateDecrypt($content);
  81. }
  82. }
  83. # 查询余额
  84. public function query($mid)
  85. {
  86. $url = $this->host() . 'uisouterfront/qrywithdrawbalance/process';
  87. $mid = $mid ? $mid : $this->mch_id;
  88. //整理内容信息
  89. $content = [
  90. 'sysId' => $this->sys_id,
  91. 'mchntNo' => $mid,
  92. 'timestamp' => date('YmdHis'),
  93. ];
  94. //设置签名并加密
  95. $body['content'] = $this->createSignature($content);
  96. $result = Dever::curl($url, $body, 'post');
  97. $decryptData = $this->privateDecrypt($result);
  98. if (isset($decryptData['tzWithdrawAmtPublic'])) {
  99. return $decryptData['tzWithdrawAmtPublic'];
  100. } elseif (isset($decryptData['t0WithdrawAmtPublic'])) {
  101. return $decryptData['t0WithdrawAmtPublic'];
  102. }
  103. return 0;
  104. }
  105. # 查询提现记录
  106. public function record($mid, $start, $end, $page = '1')
  107. {
  108. $url = $this->host() . 'uisouterfront/withdraw/qryWithDrawLog';
  109. $mid = $mid ? $mid : $this->mch_id;
  110. //整理内容信息
  111. $content = [
  112. 'sysId' => $this->sys_id,
  113. 'mchntNo' => $mid,
  114. 'timestamp' => date('YmdHis'),
  115. 'page' => (string) $page,
  116. 'beginDate' => $start,
  117. 'endDate' => $end,
  118. ];
  119. //设置签名并加密
  120. $body['content'] = $this->createSignature($content);
  121. $result = Dever::curl($url, $body, 'post');
  122. $result = Dever::json_decode($result);
  123. $decryptData = $this->privateDecrypt($result['result']);
  124. if (isset($decryptData['recordList']) && $decryptData['recordList']) {
  125. $data = Dever::json_decode($decryptData['recordList']);
  126. if ($page == 1 && isset($decryptData['totalPage']) && $decryptData['totalPage'] > 1) {
  127. for ($i = 2; $i <= $decryptData['totalPage']; $i++) {
  128. $temp = $this->record($mid, $start, $end, $i);
  129. if ($temp) {
  130. $data = array_merge($data, $temp);
  131. }
  132. }
  133. }
  134. return $data;
  135. }
  136. return array();
  137. }
  138. # 提现
  139. public function tixian($config, $merchant, $info, $auto = 1)
  140. {
  141. $url = $this->host() . 'uisouterfront/withdrawback/process';
  142. $mid = $merchant['mid'];
  143. $order_num = $info['order_num'];
  144. $cash = $info['cash'];
  145. $notify = Dever::url('yspay/single.notify?order=' . $info['order_num'], 'pay');
  146. //整理内容信息
  147. $content = [
  148. 'sysId' => $this->sys_id,
  149. 'mchntNo' => $mid,
  150. 'timestamp' => date('YmdHis'),
  151. 'sysOrderId' => $order_num,
  152. 'responseUrl' => $notify,
  153. 'withdrawType' => 2,
  154. 'withdrawAmt' => $cash,
  155. ];
  156. Dever::log($content, 'yspay_single_tixian');
  157. $data['merchant_id'] = $merchant['id'];
  158. $data['mid'] = $mid;
  159. $data['order_num'] = $order_num;
  160. $data['type'] = 2;
  161. $data['cash'] = $cash;
  162. $data['tdate'] = time();
  163. $data['status'] = 1;
  164. $data['desc'] = '';
  165. $data['mtype'] = $auto;
  166. Dever::db('pay/yspay_tixian_log')->insert($data);
  167. //设置签名并加密
  168. $body['content'] = $this->createSignature($content);
  169. $result = Dever::curl($url, $body, 'post');
  170. $decryptData = $this->privateDecrypt($result);
  171. if (isset($decryptData['responseCode']) && ($decryptData['responseCode'] == '000000' || $decryptData['responseCode'] == '000001')) {
  172. return 'ok';
  173. } else {
  174. if ($decryptData['responseDesc'] == '订单号已存在' && $info && isset($info['id'])) {
  175. Dever::db('pay/yspay_cash')->update(array('where_id' => $info['id'], 'status' => 3));
  176. }
  177. return $decryptData['responseDesc'];
  178. }
  179. }
  180. /**
  181. * 私钥解密
  182. * @Author Abnermouke <abnermouke@gmail.com>
  183. * @Originate in Abnermouke's MBP
  184. * @Time 2021-08-26 16:36:58
  185. * @param $encryptData
  186. * @return string
  187. */
  188. public function privateDecrypt($encryptData)
  189. {
  190. $content = pack('H*', $encryptData);
  191. $result = '';
  192. foreach (str_split($content, 256) as $block) {
  193. openssl_private_decrypt($block, $dataDecrypt, $this->formatRsaKey($this->private_key_pkcs1), OPENSSL_PKCS1_PADDING);
  194. $result .= $dataDecrypt;
  195. }
  196. $result = Dever::json_decode($result);
  197. return $result;
  198. }
  199. /**
  200. * 创建签名
  201. * @Author Abnermouke <abnermouke@gmail.com>
  202. * @Originate in Abnermouke's MBP
  203. * @Time 2021-08-26 16:34:49
  204. * @param $body
  205. * @return false|string
  206. */
  207. private function createSignature($body)
  208. {
  209. //重新排序信息
  210. ksort($body);
  211. //整理加密字符串
  212. $signature_string = '';
  213. //循环数据
  214. foreach ($body as $key => $value) {
  215. //整合字符串
  216. $signature_string .= $key.'='.$value.'&';
  217. }
  218. //整理加密字符串
  219. $signature_string = rtrim($signature_string, '&');
  220. //echo $signature_string;
  221. //获取加密数组
  222. $array_json = $this->rsaEncrypt($signature_string);
  223. //设置签名
  224. $body['sign'] = bin2hex($array_json);
  225. //print_r($body);
  226. //json序列化
  227. $json_data = json_encode($body);
  228. //加密RSA
  229. $json_rsa = $this->publicRsa($json_data);
  230. //返回结果
  231. return $json_rsa;
  232. }
  233. /**
  234. * 私钥加密
  235. * @Author Abnermouke <abnermouke@gmail.com>
  236. * @Originate in Abnermouke's MBP
  237. * @Time 2021-08-26 16:35:08
  238. * @param string $str
  239. * @return false
  240. */
  241. private function rsaEncrypt($str=''){
  242. $charSet = mb_detect_encoding($str, ["UTF-8", "GB2312", "GBK"]);
  243. $str = mb_convert_encoding($str, "UTF-8", $charSet);
  244. $pri_key = $this->private_key;
  245. $pri_key = $this->formatRsaKey($pri_key, 'RSA PRIVATE');
  246. $pi_key = openssl_pkey_get_private($pri_key);
  247. if(!$pi_key) return false;
  248. $algo = "SHA256";
  249. openssl_sign($str, $binary_signature, $pi_key, $algo);
  250. return $binary_signature;
  251. }
  252. /**
  253. * 公钥加密
  254. * @Author Abnermouke <abnermouke@gmail.com>
  255. * @Originate in Abnermouke's MBP
  256. * @Time 2021-08-26 16:35:14
  257. * @param string $str
  258. * @return false|string
  259. */
  260. private function publicRsa($str='')
  261. {
  262. $charSet = mb_detect_encoding($str, ["UTF-8", "GB2312", "GBK"]);
  263. $str = mb_convert_encoding($str, "UTF-8", $charSet);
  264. $pub_key = $this->public_key;
  265. $pub_key = $this->formatRsaKey($pub_key, 'PUBLIC');
  266. $pu_key = openssl_pkey_get_public($pub_key);
  267. if(!$pu_key) return false;
  268. $result = '';
  269. foreach (str_split($str,245) as $chunk) {
  270. if(openssl_public_encrypt($chunk,$encryptData, $pub_key)){
  271. $result .= $encryptData;
  272. }
  273. }
  274. $result = bin2hex($result);
  275. openssl_free_key($pu_key);
  276. return $result;
  277. }
  278. /**
  279. * 格式化密钥
  280. * @Author Abnermouke <abnermouke@gmail.com>
  281. * @Originate in Abnermouke's MBP
  282. * @Time 2021-08-26 16:36:36
  283. * @param $key
  284. * @param string $alias
  285. * @param int $length
  286. * @return string
  287. */
  288. private function formatRsaKey($key, $alias = 'RSA PRIVATE', $length = 64)
  289. {
  290. //拆分格式
  291. $key = chunk_split($key, (int)$length, "\n");
  292. //生成pem
  293. $pem = "-----BEGIN $alias KEY-----\n".$key."-----END $alias KEY-----";
  294. //返回pem
  295. return $pem;
  296. }
  297. }