params['eplpay']; if(!$eplConfig['customerCode'] || !$eplConfig['url']){ throw new Exception('缺少易票联相关配置'); } $this->eplConfig = $eplConfig; $this->wechatConfig = \Yii::$app->params['wechat']; } public static function getInstance($module = null) { if(empty(self::$instance)){ self::$instance = new self($module); } return self::$instance; } // 微信小程序支付 public function WxJsapiPayment($params){ $url = $this->eplConfig['url'].'/api/txs/pay/WxJSAPIPayment'; $param = [ 'outTradeNo' => $params['order_no'], 'customerCode' => $this->eplConfig['customerCode'], 'appId' => $this->wechatConfig['app_id'], 'openId' => $params['openId'], 'orderInfo' => $params['orderInfo'], 'payAmount' => bcmul($params['total_pay_price'], 100, 0), 'payCurrency' => 'CNY', 'payMethod' => 35, 'notifyUrl' => $this->eplConfig['pay_notify_url'], 'transactionStartTime' => date('YmdHis'), 'areaInfo' => '330102', 'nonceStr' => FuncHelper::uuid(), 'version' => '3.0' ]; $sign = $this->sign(Json::encode($param)); $result = $this->http_post_json($url,Json::encode($param),$sign); // ds(['url' => $url, 'param' => Json::encode($param), 'sign' => $sign, 'time' => date('YmdHis'), 'result' => $result]); if(!$result || $result[0] != 200){ throw new Exception('获取支付参数失败'); } return Json::decode($result[1]); } //查询支付结果 public function queryPayment($params){ $url = $this->eplConfig['url'].'/api/txs/pay/PaymentQuery'; $param = [ 'outTradeNo' => $params['pay_order_no'], 'customerCode' => $this->eplConfig['customerCode'], 'nonceStr' => FuncHelper::uuid() ]; $sign = $this->sign(Json::encode($param)); $result = $this->http_post_json($url,Json::encode($param),$sign); if(!$result || $result[0] != 200){ throw new Exception('查询支付结果失败'); } return Json::decode($result[1]); } // 退款 public function refund($params){ $url = $this->eplConfig['url'].'/api/txs/pay/Refund/V2'; $param = [ 'outRefundNo' => $params['refund_no'], 'customerCode' => $this->eplConfig['customerCode'], 'transactionNo' => $params['transaction_id'], 'amount' => bcmul($params['total_pay_price'], 100, 0), 'refundAmount' => bcmul($params['refund_price'], 100, 0), 'notifyUrl' => $this->eplConfig['refund_notify_url'], 'transactionStartTime' => date('YmdHis'), 'nonceStr' => FuncHelper::uuid(), 'version' => '3.0' ]; $sign = $this->sign(Json::encode($param)); $result = $this->http_post_json($url,Json::encode($param),$sign); if(!$result || $result[0] != 200){ throw new Exception('退款失败'); } return Json::decode($result[1]); } //查询退款结果 public function queryRefund($params){ $url = $this->eplConfig['url'].'/api/txs-query/refundOrderQuery'; $param = [ 'outRefundNo' => $params['refund_no'], 'customerCode' => $this->eplConfig['customerCode'], 'nonceStr' => FuncHelper::uuid() ]; $sign = $this->sign(Json::encode($param)); $result = $this->http_post_json($url,Json::encode($param),$sign); if(!$result || $result[0] != 200){ throw new Exception('查询退款结果失败'); } return Json::decode($result[1]); } //单笔提现 public function withDraw($params){ // 构建请求提现接口的URL $url = $this->eplConfig['url'].'/api/txs/pay/withdrawalToCard'; // 构建请求参数数组 $param = [ // 设置商户订单号 'outTradeNo' => $params['order_no'], // 设置客户代码 'customerCode' => $this->eplConfig['customerCode'], // 设置提现金额,将申请的现金金额乘以100,转换为分 'amount' => bcmul($params['apply_cash'], 100, 0), // 设置到账类型,0表示当日到账 'arrivalType' => 0, // 设置手续费扣除方式,内扣或外扣 inner内扣 outer外扣 'procedureType' => 'inner', // 设置开户人姓名,使用公钥加密 'bankUserName' => $this->public_encrypt($params['bank_user_name']), // 设置银行卡号,使用公钥加密 'bankCardNo' => $this->public_encrypt($params['bank_card']), // 设置银行名称 'bankName' => $params['bank_name'], // 设置账户类型,对公、对私或存折 1对公 2对私 5存折 'bankAccountType' => $params['bank_account_type'], // 设置服务器回调通知URL 'notifyUrl' => $this->eplConfig['withdraw_notify_url'], // 设置支付货币类型 'payCurrency' => 'CNY', // 设置随机字符串 'nonceStr' => FuncHelper::uuid() ]; // 根据银行账户类型和银行卡号的前两位判断是否需要设置银行代码 if($params['bank_account_type'] != '2' || substr($params['bank_card'],0,2) != '62'){ $param['bankNo'] = $params['bank_no']; } // 生成请求的签名 $sign = $this->sign(Json::encode($param)); // 发起提现请求 $result = $this->http_post_json($url,Json::encode($param),$sign); // 验证请求结果,如果结果为空或HTTP状态码不是200,则抛出异常 if(!$result || $result[0] != 200){ throw new Exception('提现失败'); } // 解析并返回提现请求的结果 return Json::decode($result[1]); } //查询提现结果 public function queryWithdraw($params){ $url = $this->eplConfig['url'].'/api/txs/pay/withdrawalToCardQuery'; $param = [ 'outTradeNo' => $params['withdraw_order_no'], 'customerCode' => $this->eplConfig['customerCode'], 'nonceStr' => FuncHelper::uuid() ]; $sign = $this->sign(Json::encode($param)); $result = $this->http_post_json($url,Json::encode($param),$sign); if(!$result || $result[0] != 200){ throw new Exception('查询提现结果失败'); } return Json::decode($result[1]); } protected function sign($data) { $certs = []; openssl_pkcs12_read(file_get_contents($this->eplConfig['rsaPrivateKeyFilePath']), $certs, $this->eplConfig['password']); //其中password为你的证书密码 if(!$certs){ throw new Exception('请检查RSA私钥配置'. openssl_error_string()); } openssl_sign($data, $sign, $certs['pkey'], OPENSSL_ALGO_SHA256); $sign = base64_encode($sign); return $sign; } protected function http_post_json($url, $jsonStr, $sign) { $ch = curl_init(); $headers = array( 'Content-Type: application/json; charset=utf-8', 'Content-Length: ' . strlen($jsonStr), 'x-efps-sign-no:'.$this->eplConfig['signNo'], 'x-efps-sign-type:SHA256withRSA', 'x-efps-sign:'.$sign, 'x-efps-timestamp:'.date('YmdHis'), ); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonStr); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 跳过检查 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // 跳过检查 //curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); return [$httpCode, $response]; } // 公钥加密 protected function public_encrypt($data) { //读取公钥文件 $pubKey = file_get_contents($this->eplConfig['publicKeyFilePath']); $res = openssl_get_publickey($pubKey); if(!$res){ throw new Exception('RSA公钥错误。请检查公钥文件格式是否正确'); } $crypttext = ""; openssl_public_encrypt($data,$crypttext, $res ); if(!$this->checkEmpty($this->eplConfig['publicKeyFilePath'])) { //释放资源 if (PHP_VERSION_ID < 80000) { openssl_free_key($res); } } return(base64_encode($crypttext)); } /** * 校验$value是否非空 * if not set ,return true; * if is null , return true; **/ protected function checkEmpty($value) { if (!isset($value)) return true; if ($value === null) return true; if (trim($value) === "") return true; return false; } }