Xcx.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. <?php
  2. namespace app\expand\controller;
  3. use app\common\service\HelperService;
  4. use app\common\service\wechat\decode\WXBizDataCrypt;
  5. use app\common\service\wechat\UnifiedOrder_pub;
  6. use think\Config;
  7. use think\Validate;
  8. use think\Log;
  9. /**
  10. * 小程序支付接口
  11. * Class WeChat
  12. * @package app\expand\controller
  13. */
  14. class Xcx extends BaseAuth
  15. {
  16. private $_Account = null;
  17. private $_APPID = null;
  18. private $_MCHID = null;
  19. private $_SUBMCHID = null;
  20. private $_SUBAPPID = null;
  21. private $_PayTip = "";
  22. public function __construct(){
  23. parent::__construct();
  24. if($this->_inWhiteList == true){
  25. return ;
  26. }
  27. $this->_Account = $this->getKey($this->_apiCode);
  28. //验证是否具有访问这个接口的权限
  29. if(!isset($this->_Account['Xcx_pay_appId'])
  30. || !isset($this->_Account['Xcx_mchId'])
  31. || !isset($this->_Account['Xcx_pay_key'])){
  32. HelperService::returnJson(['code'=>400,'msg'=>'Xcx interface unauthorized access','data'=>$this->_Account]);
  33. }
  34. $this->_APPID = $this->_Account['Xcx_pay_appId'];
  35. $this->_MCHID = $this->_Account['Xcx_mchId'];
  36. $this->_SUBMCHID = isset($this->_Account['Xcx_sub_mchId'])?$this->_Account['Xcx_sub_mchId']:"";
  37. $this->_SUBAPPID = isset($this->_Account['Xcx_pay_sub_appId'])?$this->_Account['Xcx_pay_sub_appId']:"";
  38. $this->_PayTip = isset($this->_Account['Xcx_tip'])?$this->_Account['Xcx_tip']:"";
  39. Config::set('WECHAT_APPID',$this->_APPID);
  40. Config::set('WECHAT_MCHID',$this->_MCHID);
  41. Config::set('WECHAT_SUB_MCHID',$this->_SUBMCHID);
  42. Config::set('WECHAT_SUB_APPID',$this->_SUBAPPID);
  43. Config::set('WECHAT_PAY_KEY',$this->_Account['Xcx_pay_key']);
  44. }
  45. /**
  46. * 平台版支付接口
  47. */
  48. public function platformXcxPay(){
  49. $params = $this->_params;
  50. $rule = [
  51. 'order_no|订单号'=>'require',
  52. 'total_fee|支付金额'=>'require',
  53. 'openid|小程序的openid'=>'require',
  54. 'tip|商品信息'=>'max:500'
  55. ];
  56. $validate = new Validate($rule);
  57. if(!$validate->check($params)){
  58. HelperService::returnJson(['code'=>400,'msg'=>$validate->getError(),'data'=>[]]);
  59. }
  60. require_once(APP_PATH.'/common/service/wechat/WxPayPubHelper.php');
  61. $unifiedOrder = new UnifiedOrder_pub();
  62. //设置统一支付接口参数
  63. //$unifiedOrder->setParameter("openid", "{$params['openid']}"); //商品描述
  64. $body = $this->_PayTip;
  65. if(!empty($params['tip'])){
  66. $body = $params['tip'];
  67. }
  68. if(empty($body)){
  69. $body = $this->_apiCode;
  70. }
  71. $unifiedOrder->setParameter("body",$body."[". substr($params['order_no'],-8)."]"); //商品描述
  72. $unifiedOrder->setParameter("attach",$body); //商品描述
  73. //自定义订单号,此处仅作举例
  74. $out_trade_no = $this->_apiCode."_".$params['order_no']."_".rand(10,99);
  75. $unifiedOrder->setParameter("out_trade_no", $out_trade_no); //商户订单号
  76. $unifiedOrder->setParameter("total_fee", $params['total_fee']); //总金额
  77. $unifiedOrder->setParameter("sub_openid", $params['openid']); //总金额
  78. $httpHeader = HelperService::getHttpHeader();
  79. $unifiedOrder->setParameter("notify_url", "{$httpHeader}{$_SERVER['HTTP_HOST']}/v1/notifyXcxPay"); //通知地址
  80. $unifiedOrder->setParameter("trade_type", "JSAPI"); //交易类型
  81. $prepay_id = $unifiedOrder->getPrepayId();
  82. $appId = empty($this->_SUBAPPID)?$this->_APPID:$this->_SUBAPPID;
  83. $returnData = [
  84. 'appId'=>$appId,
  85. 'timeStamp'=>time(),
  86. 'nonceStr'=> uniqid(),
  87. 'package'=>"prepay_id=$prepay_id",
  88. 'signType'=>'MD5',
  89. ];
  90. $returnData['paySign'] = $unifiedOrder->getSign($returnData);
  91. HelperService::returnJson([
  92. 'data'=>$returnData,
  93. 'msg'=>'success',
  94. 'code'=>200
  95. ]);
  96. }
  97. /**
  98. * 获取微信相关信息
  99. */
  100. public function getOpenInfo(){
  101. $params = $this->_params;
  102. $rule = [
  103. 'code|js获取的code'=>'require',
  104. ];
  105. $validate = new Validate($rule);
  106. if(!$validate->check($params)){
  107. HelperService::returnJson(['code'=>400,'msg'=>$validate->getError(),'data'=>[]]);
  108. }
  109. if(empty($this->_Account['Xcx_secret'])){
  110. HelperService::returnJson(['code'=>400,'msg'=>'Xcx getOpenInfo unauthorized access','data'=>$this->_Account]);
  111. }
  112. $secret = $this->_Account['Xcx_secret'];
  113. $appId = empty($this->_SUBAPPID)?$this->_APPID:$this->_SUBAPPID;
  114. $url = "https://api.weixin.qq.com/sns/jscode2session?appid={$appId}&secret={$secret}&js_code={$params['code']}&grant_type=authorization_code";
  115. $openInfoJson = file_get_contents($url);
  116. $openInfo = @json_decode($openInfoJson,true);
  117. if($openInfo===false || !empty($openInfo['errcode'])){
  118. HelperService::returnJson([
  119. 'data'=>$openInfoJson,'msg'=>'fail','code'=>400
  120. ]);
  121. }
  122. HelperService::returnJson([
  123. 'data'=> array_merge($openInfo,['appId'=>$appId]),'msg'=>'success','code'=>200
  124. ]);
  125. }
  126. public function getMobileInfo() {
  127. $params = $this->_params;
  128. $rule = [
  129. 'code|js获取的code'=>'require',
  130. 'encryptedData'=>'require',
  131. 'iv'=>'require'
  132. ];
  133. $validate = new Validate($rule);
  134. if(!$validate->check($params)){
  135. HelperService::returnJson(['code'=>400,'msg'=>$validate->getError(),'data'=>[]]);
  136. }
  137. if(empty($this->_Account['Xcx_secret'])){
  138. HelperService::returnJson(['code'=>400,'msg'=>'Xcx getOpenInfo unauthorized access','data'=>$this->_Account]);
  139. }
  140. $secret = $this->_Account['Xcx_secret'];
  141. $appId = empty($this->_SUBAPPID)?$this->_APPID:$this->_SUBAPPID;
  142. $url = "https://api.weixin.qq.com/sns/jscode2session?appid={$appId}&secret={$secret}&js_code={$params['code']}&grant_type=authorization_code";
  143. $openInfoJson = file_get_contents($url);
  144. $openInfo = @json_decode($openInfoJson,true);
  145. if($openInfo===false || !empty($openInfo['errcode'])){
  146. HelperService::returnJson([
  147. 'data'=>$openInfoJson,'msg'=>'fail','code'=>400
  148. ]);
  149. }
  150. $pc = new WXBizDataCrypt($appId, $openInfo['session_key']);
  151. $errCode = $pc->decryptData($params['encryptedData'], $params['iv'], $data);
  152. if ($errCode == 0) {
  153. $data = json_decode($data,true);
  154. HelperService::returnJson([
  155. 'data'=> array_merge($data,['appId'=>$appId]),'msg'=>'success','code'=>200
  156. ]);
  157. }
  158. HelperService::returnJson([
  159. 'data'=>[],'msg'=>'获取手机号失败请重试','code'=>400
  160. ]);
  161. }
  162. /**
  163. * 异步通知小程序支付
  164. */
  165. public function notifyXcxPay(){
  166. $this->getInput();
  167. $param = $this->_oldParams;
  168. $this->_sysParams['request_ts'] = time();
  169. Log::record($param);
  170. $params = (array)@simplexml_load_string($param, 'SimpleXMLElement', LIBXML_NOCDATA);
  171. if(empty($params)){
  172. HelperService::returnJson(['code' => 400, 'msg' => "参数错误",'data'=>['baseParams'=>$param]]);
  173. }
  174. try {
  175. $arr = ['total_fee', 'out_trade_no'];
  176. foreach ($arr as $key=>$value) {
  177. if (!isset($params[$value])) {
  178. HelperService::returnJson(['code' => 400, 'msg' => "参数错误({$key})",'data'=>['baseParams'=>$param]]);
  179. }
  180. }
  181. $tradeNoArr = explode('_', $params['out_trade_no']);
  182. if(count($tradeNoArr)<2){
  183. HelperService::returnJson(['code' => 400, 'msg' => "参数错误(trade)",'data'=>['baseParams'=>$param]]);
  184. }
  185. $companyCode = $tradeNoArr[0];
  186. $this->_Account = $this->getKey($companyCode,false);//不验证参数
  187. $orderNo = isset($tradeNoArr[1]) ? $tradeNoArr[1] : 0;
  188. //开发分发给不同的支付主体
  189. if(!isset($this->_Account['Xcx_pay_notify_url'])
  190. || empty($this->_Account['Xcx_pay_notify_url'])){
  191. HelperService::returnJson(['code' => 400, 'msg' => "回调地址不存在",'data'=>['baseParams'=>$param]]);
  192. }
  193. if(!is_array($this->_Account['Xcx_pay_notify_url'])){
  194. HelperService::returnJson(['code' => 400, 'msg' => "回调地址不是数组",'data'=>['baseParams'=>$param]]);
  195. }
  196. $notifyUrlArr = $this->_Account['Xcx_pay_notify_url'];
  197. foreach($notifyUrlArr as $url){
  198. $is_ssl = strpos($url, 'https://')!==false?true:false;
  199. $data = [
  200. 'order_no'=>$orderNo,
  201. 'total_price'=>"{$params['total_fee']}",
  202. 'out_trade_no'=>"{$params['out_trade_no']}"
  203. ];
  204. $times = 3;
  205. while($times--){
  206. $res = HelperService::httpPost($url,json_encode($data),$is_ssl);
  207. HelperService::addLog(['item'=>$url,'data'=>$data,'result'=>$res,'times'=>$times],$url,'XCXPAY_DETAIL');
  208. //file_put_contents('ABC_TEMP' ,var_export(['item'=>$url,'data'=>$data,'result'=>$res,'times'=>$times],true),FILE_APPEND);
  209. if($res != false){
  210. break;
  211. }
  212. }
  213. if($times ==0){
  214. Log::record("小程序支付推送异常=>url:".$url."=>res:". json_encode($res)."=>data:". json_encode($data));
  215. }
  216. }
  217. die('success');
  218. }catch (\Exception $ex){
  219. file_put_contents('xcxPayRecord-Exception.mp',"[".date('Y-m-d H:i:s')."]".$ex->getMessage().json_encode($params)."\n\n",FILE_APPEND);
  220. }
  221. }
  222. }