Yspay.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. <?php namespace Pay\Lib;
  2. use Dever;
  3. class Yspay extends Core
  4. {
  5. public function __construct($config)
  6. {
  7. $project = Dever::project('pay');
  8. # 通知接口
  9. $config['notify'] = $this->url($config['type'], $config['id']);
  10. $set = explode('|', $config['mchid']);
  11. $config['mid'] = $set[0];
  12. $config['tid'] = $set[1];
  13. if (isset($set[2])) {
  14. $config['prefix'] = $set[2];
  15. }
  16. $set = explode('|', $config['key']);
  17. $config['sub_appid'] = $set[0];
  18. $config['sub_appsecret'] = $set[1];
  19. $this->config = $config;
  20. }
  21. /**
  22. * 通知
  23. */
  24. public function notify()
  25. {
  26. $input = file_get_contents("php://input");
  27. if ($input) {
  28. parse_str($input, $input);
  29. } else {
  30. $input = Dever::input();
  31. }
  32. $this->log('支付回调-初始化', $input);
  33. echo 'FAILED';die;
  34. return;
  35. ksort($input);
  36. $input = http_build_query($input);
  37. $tools = new \Cmbc\Handle();
  38. $callback = $tools->get('notify', $this->config);
  39. $result = $callback->request($input, $this);
  40. if ($result) {
  41. $this->log('支付回调-获取数据', $result);
  42. $this->updateOrder($result['mhtOrderNo'], $result['mhtOrderAmt']);
  43. echo 'SUCCESS';die;
  44. } else {
  45. echo 'FAILED';die;
  46. }
  47. }
  48. /**
  49. * 获取统一下单的基本信息
  50. */
  51. public function order($account_id, $project_id, $uid, $username, $product_id, $name, $cash, $openid = false, $type = 1, $order_id = false, $other = false)
  52. {
  53. $trade_type = $this->getType($type);
  54. $order_id = $this->createOrder($uid, $username, $account_id, $project_id, $product_id, $name, $cash, $this->config['type'], $order_id);
  55. if (isset($this->config['prefix']) && $this->config['prefix']) {
  56. $request['merOrderId'] = $this->config['prefix'] . '_' . $order_id;
  57. } else {
  58. $request['merOrderId'] = $order_id;
  59. }
  60. $request['mid'] = $this->config['mid'];
  61. $request['tid'] = $this->config['tid'];
  62. $request['instMid'] = 'MINIDEFAULT';
  63. $request['totalAmount'] = $cash * 100;
  64. //$request['totalAmount'] = 100;
  65. $request['subAppId'] = $this->config['sub_appid'];
  66. $request['requestTimestamp'] = date("Y-m-d H:i:s");
  67. $request['expireTime'] = date("Y-m-d H:i:s", time() + $this->config['timeout']);
  68. $request['notifyUrl'] = $this->config['notify'];
  69. $request['tradeType'] = 'MINI';
  70. if ($other) {
  71. $request['originalAmount'] = $other['oprice'];
  72. $request['divisionFlag'] = true;
  73. # 平台分账金额
  74. $other['per'] = $other['per']/100;
  75. $request['platformAmount'] = $request['totalAmount'] * $other['per'];
  76. $request['subOrders'] = array();
  77. $request['subOrders']['mid'] = $other['mid'];
  78. if (isset($this->config['prefix']) && $this->config['prefix']) {
  79. $request['subOrders']['merOrderId'] = $this->config['prefix'] . '_' . $other['order_id'];
  80. } else {
  81. $request['subOrders']['merOrderId'] = $other['order_id'];
  82. }
  83. $request['subOrders']['totalAmount'] = $request['totalAmount'] - $request['platformAmount'];
  84. $request['subOrders'] = array($request['subOrders']);
  85. }
  86. if (!$openid) {
  87. # 测试的openid
  88. $request['subOpenId'] = 'ofBUV0RUoy_8C4VctZjrSDGzhUfY';
  89. } else {
  90. $request['subOpenId'] = $openid;
  91. }
  92. $result = Base::pay($request, $this->config);
  93. if (isset($result['miniPayRequest'])) {
  94. $result['request'] = $request;
  95. $result['payMsg'] = $result['miniPayRequest'];
  96. unset($result['miniPayRequest']);
  97. if ($other) {
  98. $result['other'] = $other;
  99. }
  100. $this->updateOrderParam($order_id, $result);
  101. return $result['payMsg'];
  102. } else {
  103. return false;
  104. }
  105. }
  106. # 退款
  107. public function refund($order_id, $cash, $order, $refund_order_id = false)
  108. {
  109. if (isset($this->config['prefix']) && $this->config['prefix']) {
  110. $request['merOrderId'] = $this->config['prefix'] . '_' . $order_id;
  111. if ($refund_order_id) {
  112. $request['refundOrderId'] = $this->config['prefix'] . '_' . $refund_order_id;
  113. }
  114. } else {
  115. $request['merOrderId'] = $order_id;
  116. if ($refund_order_id) {
  117. $request['refundOrderId'] = $refund_order_id;
  118. }
  119. }
  120. $request['mid'] = $this->config['mid'];
  121. $request['tid'] = $this->config['tid'];
  122. $request['instMid'] = 'MINIDEFAULT';
  123. if (isset($order['param']['targetOrderId'])) {
  124. $request['targetOrderId'] = $order['param']['targetOrderId'];
  125. }
  126. $request['subAppId'] = $this->config['appid'];
  127. $request['requestTimestamp'] = date("Y-m-d H:i:s");
  128. $request['refundAmount'] = $cash * 100;
  129. if (isset($order['param']['other']) && $order['param']['other']) {
  130. $other = $order['param']['other'];
  131. $other['per'] = $other['per']/100;
  132. $request['platformAmount'] = $request['refundAmount'] * $other['per'];
  133. $request['subOrders'] = array();
  134. $request['subOrders']['mid'] = $other['mid'];
  135. if (isset($this->config['prefix']) && $this->config['prefix']) {
  136. $request['subOrders']['merOrderId'] = $this->config['prefix'] . '_' . $other['order_id'];
  137. if ($refund_order_id) {
  138. $request['subOrders']['refundOrderId'] = $this->config['prefix'] . '_' . $refund_order_id;
  139. }
  140. } else {
  141. $request['subOrders']['merOrderId'] = $other['order_id'];
  142. if ($refund_order_id) {
  143. $request['subOrders']['refundOrderId'] = $refund_order_id;
  144. }
  145. }
  146. $request['subOrders']['totalAmount'] = $request['refundAmount'] - $request['platformAmount'];
  147. $request['subOrders'] = array($request['subOrders']);
  148. }
  149. $result = Base::refund($request, $this->config);
  150. if (isset($result['refundStatus']) && $result['refundStatus'] == 'SUCCESS') {
  151. return true;
  152. }
  153. return false;
  154. }
  155. # 查询
  156. public function query($order_id)
  157. {
  158. $request['merOrderId'] = $order_id;
  159. $request['mid'] = $this->config['mchid'];
  160. $request['tid'] = $this->config['key'];
  161. $request['instMid'] = 'MINIDEFAULT';
  162. $request['requestTimestamp'] = date("Y-m-d H:i:s");
  163. $result = Base::refund($request, $this->config);
  164. return $result;
  165. }
  166. # 关闭订单
  167. public function close($order_id)
  168. {
  169. $request['merOrderId'] = $order_id;
  170. $request['mid'] = $this->config['mchid'];
  171. $request['tid'] = $this->config['key'];
  172. $request['instMid'] = 'MINIDEFAULT';
  173. $request['requestTimestamp'] = date("Y-m-d H:i:s");
  174. $result = Base::close($request, $this->config);
  175. return $result;
  176. }
  177. /**
  178. * 获取二维码支付
  179. */
  180. public function qrcode($order, $refer)
  181. {
  182. $notify = new \NativePay();
  183. $result = $notify->GetPayUrl($order);
  184. $url = $result['code_url'];
  185. return $url;
  186. }
  187. /**
  188. * 获取小程序支付
  189. */
  190. public function applet($order)
  191. {
  192. $result = array();
  193. if (isset($order['package'])) {
  194. $prepay_id = str_replace('prepay_id=', '', $order['package']);
  195. $result['time'] = $order['timeStamp'];
  196. $result['nonce_str'] = $order['nonceStr'];
  197. $result['prepay_id'] = $prepay_id;
  198. $result['sign_type'] = $order['signType'];
  199. $result['sign'] = $order['paySign'];
  200. }
  201. return $result;
  202. }
  203. /**
  204. * 获取页面支付
  205. */
  206. public function page($order, $refer)
  207. {
  208. $refer = urldecode($refer);
  209. $tools = new \JsApiPay($this->config);
  210. $info = $tools->GetJsApiParameters($order);
  211. $html = '<script type="text/javascript">
  212. function jsApiCall()
  213. {
  214. WeixinJSBridge.invoke(
  215. "getBrandWCPayRequest",
  216. '.$info.',
  217. function(res){
  218. //WeixinJSBridge.log(res.err_msg);
  219. if(res.err_msg == "get_brand_wcpay_request:ok")
  220. {
  221. location.href = "'.$refer.'";
  222. } else {
  223. alert(res.err_code+res.err_desc+res.err_msg);
  224. }
  225. }
  226. );
  227. }
  228. function callpay()
  229. {
  230. if (typeof WeixinJSBridge == "undefined"){
  231. if( document.addEventListener ){
  232. document.addEventListener("WeixinJSBridgeReady", jsApiCall, false);
  233. }else if (document.attachEvent){
  234. document.attachEvent("WeixinJSBridgeReady", jsApiCall);
  235. document.attachEvent("onWeixinJSBridgeReady", jsApiCall);
  236. }
  237. }else{
  238. jsApiCall();
  239. }
  240. }
  241. callpay();
  242. </script>';
  243. return $html;
  244. }
  245. private function getType($type)
  246. {
  247. switch ($type) {
  248. case 1:
  249. $type = 'JSAPI';
  250. break;
  251. case 2:
  252. $type = 'NATIVE';
  253. break;
  254. case 3:
  255. $type = 'APP';
  256. break;
  257. case 4:
  258. $type = 'MWEB';
  259. break;
  260. }
  261. return $type;
  262. }
  263. }
  264. class Base
  265. {
  266. static $test_host = 'https://test-api-open.chinaums.com/';
  267. static $host = 'https://api-mop.chinaums.com/';
  268. static $signMethod = 'SHA256'; //签名方式
  269. # 获取token
  270. static $token_url = 'v1/token/access';
  271. # 微信下单支付
  272. static $pay_wechat_url = 'v1/netpay/wx/unified-order';
  273. # 支付宝下单支付
  274. static $pay_alipay_url = 'v1/netpay/trade/create';
  275. # 云闪付下单支付
  276. static $pay_uac_url = 'v1/netpay/uac/mini-order';
  277. # 交易查询
  278. static $query_url = 'v1/netpay/query';
  279. # 退款
  280. static $refund_url = 'v1/netpay/refund';
  281. # 退款查询
  282. static $refund_query_url = 'v1/netpay/refund-query';
  283. # 订单关闭
  284. static $close_url = 'v1/netpay/close';
  285. //===================== 支付相关 ==============================
  286. /**
  287. * 支付交易
  288. */
  289. static public function pay($param, $config)
  290. {
  291. $url = self::$pay_wechat_url;
  292. $result = self::get($url, $param, $config);
  293. return $result;
  294. }
  295. /**
  296. * 支付撤销
  297. */
  298. static public function close()
  299. {
  300. $url = self::$close_url;
  301. $result = self::get($url, $param, $config);
  302. return $result;
  303. }
  304. /**
  305. * 交易退款
  306. */
  307. static public function refund($param, $config)
  308. {
  309. $url = self::$refund_url;
  310. $result = self::get($url, $param, $config);
  311. return $result;
  312. }
  313. /**
  314. * 交易查询
  315. */
  316. static public function query()
  317. {
  318. $url = self::$query_url;
  319. $result = self::get($url, $param, $config);
  320. return $result;
  321. }
  322. /**
  323. * 交易退款查询
  324. */
  325. static public function refundQuery()
  326. {
  327. $url = self::$refund_query_url;
  328. $result = self::get($url, $param, $config);
  329. return $result;
  330. }
  331. //====================== 获取调用凭证===========================
  332. /**
  333. * 通用调用凭证获取
  334. * 默认使用token方式,使用签名方式需要传入参数
  335. */
  336. static public function getAuth($type = 'token', $param, $config)
  337. {
  338. if ($type === 'token') {
  339. return self::getAccessTokenByToken($config);
  340. }
  341. return self::getAccessTokenBySig($param, $config);
  342. }
  343. /**
  344. * 方式一,OPEN-ACCESS-TOKEN方式
  345. */
  346. static function getAccessTokenByToken($config)
  347. {
  348. $param = [
  349. 'appId' => $config['appid'],
  350. 'timestamp' => date('YmdHis'),
  351. 'nonce' => md5(uniqid(microtime(true),true)),
  352. 'signMethod' => self::$signMethod,
  353. ];
  354. $param['signature'] = self::signature($param, $config['appsecret']);
  355. $result = self::get(self::$token_url, $param, $config);
  356. if (isset($result['errCode']) && isset($result['accessToken'])) {
  357. return 'OPEN-ACCESS-TOKEN AccessToken='.$result['accessToken'];
  358. }
  359. return '';
  360. }
  361. /**
  362. * 方式二,OPEN-BODY-SIG方式
  363. */
  364. static function getAccessTokenBySig($data, $config)
  365. {
  366. $param = [
  367. 'AppId' => $config['appid'],
  368. 'Timestamp' => date('YmdHis'),
  369. 'Nonce' => md5(uniqid(microtime(true),true))
  370. ];
  371. return 'OPEN-BODY-SIG AppId="'.$param['AppId'].'", Timestamp="'.$param['Timestamp'].'", Nonce="'.$param['Nonce'].'", Signature="'.self::signature2($data, $param, $config['appsecret']).'"';
  372. }
  373. /**
  374. * 计算签名,方式一
  375. */
  376. static function signature($param, $appsecret)
  377. {
  378. return bin2hex(hash(self::$signMethod, $param['appId'].$param['timestamp'].$param['nonce'].$appsecret, true));
  379. }
  380. /**
  381. * 计算签名,方式二
  382. */
  383. static function signature2($data, $param, $appsecret)
  384. {
  385. $str = bin2hex(hash('sha256', Dever::json_encode($data), true));
  386. return base64_encode(hash_hmac('sha256', $param['AppId'].$param['Timestamp'].$param['Nonce'].$str, $appsecret, true));
  387. }
  388. /**
  389. * 获取信息
  390. */
  391. static function get($url, $param, $config)
  392. {
  393. $url = $config['box'] == 1 ? self::$host . $url : self::$test_host . $url;
  394. $header = array();
  395. $header['Authorization'] = self::getAuth('sig', $param, $config);
  396. $result = Dever::curl($url, $param, 'post', true, $header);
  397. if (strstr($result, '<html><head>')) {
  398. Dever::alert('系统错误');
  399. }
  400. $result = Dever::json_decode($result);
  401. if (isset($result['errCode'])) {
  402. if ($result['errCode'] == '0000' || $result['errCode'] == 'SUCCESS') {
  403. return $result;
  404. } elseif (isset($result['errInfo'])) {
  405. Dever::alert($result['errInfo']);
  406. } elseif (isset($result['errMsg'])) {
  407. Dever::alert($result['errMsg']);
  408. }
  409. } else {
  410. Dever::alert('系统错误');
  411. }
  412. return $result;
  413. }
  414. }