config = new DataArray($options); $this->params = new DataArray([ 'appid' => $this->config->get('appid'), 'mch_id' => $this->config->get('mch_id'), 'nonce_str' => Tools::createNoncestr(), ]); } /** * 统一下单 * @param array $options * @return array * @throws InvalidResponseException */ public function createOrder(array $options) { $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; return $this->callPostApi($url, $options, false, 'MD5'); } /** * 创建JsApi及H5支付参数 * @param string $prepay_id 统一下单预支付码 * @return array */ public function createParamsForJsApi($prepay_id) { $option = []; $option["appId"] = $this->config->get('appid'); $option["timeStamp"] = (string)time(); $option["nonceStr"] = Tools::createNoncestr(); $option["package"] = "prepay_id={$prepay_id}"; $option["signType"] = "MD5"; $option["paySign"] = $this->getPaySign($option, 'MD5'); $option['timestamp'] = $option['timeStamp']; return $option; } /** * 获取支付规则二维码 * @param string $product_id 商户定义的商品id 或者订单号 * @return string */ public function createParamsForRuleQrc($product_id) { $data = [ 'appid' => $this->config->get('appid'), 'mch_id' => $this->config->get('mch_id'), 'time_stamp' => (string)time(), 'nonce_str' => Tools::createNoncestr(), 'product_id' => (string)$product_id, ]; $data['sign'] = $this->getPaySign($data, 'MD5'); return "weixin://wxpay/bizpayurl?" . http_build_query($data); } /** * 查询订单 * @param array $options * @return array * @throws InvalidResponseException */ public function queryOrder(array $options) { $url = 'https://api.mch.weixin.qq.com/pay/orderquery'; return $this->callPostApi($url, $options); } /** * 关闭订单 * @param string $out_trade_no 商户订单号 * @return array * @throws InvalidResponseException */ public function closeOrder($out_trade_no) { $url = 'https://api.mch.weixin.qq.com/pay/closeorder'; return $this->callPostApi($url, ['out_trade_no' => $out_trade_no]); } /** * 申请退款 * @param array $options * @return array * @throws InvalidResponseException */ public function createRefund(array $options) { $url = 'https://api.mch.weixin.qq.com/secapi/pay/refund'; return $this->callPostApi($url, $options, true); } /** * 查询退款 * @param array $options * @return array * @throws InvalidResponseException */ public function queryRefund(array $options) { $url = 'https://api.mch.weixin.qq.com/pay/refundquery'; return $this->callPostApi($url, $options); } /** * 交易保障 * @param array $options * @return array * @throws InvalidResponseException */ public function report(array $options) { $url = 'https://api.mch.weixin.qq.com/payitil/report'; return $this->callPostApi($url, $options); } /** * 授权码查询openid * @param string $authCode 扫码支付授权码,设备读取用户微信中的条码或者二维码信息 * @return array * @throws InvalidResponseException */ public function queryAuthCode($authCode) { $url = 'https://api.mch.weixin.qq.com/tools/authcodetoopenid'; return $this->callPostApi($url, ['auth_code' => $authCode]); } /** * 转换短链接 * @param string $longUrl 需要转换的URL,签名用原串,传输需URLencode * @return array * @throws InvalidResponseException */ public function shortUrl($longUrl) { $url = 'https://api.mch.weixin.qq.com/tools/shorturl'; return $this->callPostApi($url, ['long_url' => $longUrl]); } /** * 下载对账单 * @param array $options * @return array * @throws InvalidResponseException */ public function billDownload(array $options) { $url = 'https://api.mch.weixin.qq.com/pay/downloadbill'; return $this->callPostApi($url, $options); } /** * 拉取订单评价数据 * @param array $options * @return array * @throws InvalidResponseException */ public function billCommtent(array $options) { $url = 'https://api.mch.weixin.qq.com/billcommentsp/batchquerycomment'; return $this->callPostApi($url, $options, true); } /** * 企业付款到零钱 * @param array $options * @return array * @throws InvalidResponseException */ public function createTransfers(array $options) { $this->params->set('mchid', $this->config->get('mch_id')); $this->params->set('mch_appid', $this->config->get('appid')); $this->params->offsetUnset('appid'); $this->params->offsetUnset('mch_id'); $url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers'; return $this->callPostApi($url, $options, true, 'MD5', false); } /** * 查询企业付款到零钱 * @param string $partner_trade_no 商户调用企业付款API时使用的商户订单号 * @return array * @throws InvalidResponseException */ public function queryTransfers($partner_trade_no) { $url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo'; return $this->callPostApi($url, ['partner_trade_no' => $partner_trade_no], true, 'MD5', false); } /** * 获取微信支付通知 * @return array * @throws InvalidResponseException */ public function getNotify() { $data = Tools::xml2arr(file_get_contents('php://input')); if (!empty($data['sign'])) { if ($this->getPaySign($data) === $data['sign']) { return $data; } } throw new InvalidResponseException('Invalid Notify.', '0'); } /** * 生成支付签名 * @param array $data 参与签名的数据 * @param string $signType 参与签名的类型 * @param string $buff 参与签名字符串前缀 * @return string */ public function getPaySign(array $data, $signType = 'MD5', $buff = '') { unset($data['sign']); ksort($data); foreach ($data as $k => $v) { $buff .= "{$k}={$v}&"; } $buff .= ("key=" . $this->config->get('mch_key')); if (strtoupper($signType) === 'MD5') { return strtoupper(md5($buff)); } return strtoupper(hash_hmac('SHA256', $buff, $this->config->get('mch_key'))); } /** * 以Post请求接口 * @param string $url 请求 * @param array $data 接口参数 * @param bool $isCert 是否需要使用双向证书 * @param string $signType 数据签名类型 MD5|SHA256 * @param bool $needSignType 是否需要传签名类型参数 * @return array * @throws InvalidResponseException */ public function callPostApi($url, array $data, $isCert = false, $signType = 'HMAC-SHA256', $needSignType = true) { $option = []; if ($isCert) { $option['ssl_cer'] = $this->config->get('ssl_cer'); $option['ssl_key'] = $this->config->get('ssl_key'); foreach (['ssl_cer', 'ssl_key'] as $key) { if (empty($option[$key]) || !file_exists($option[$key])) { throw new InvalidArgumentException("Missing Config -- [{$key}]", '0'); } } } $params = $this->params->merge($data); $needSignType && ($params['sign_type'] = strtoupper($signType)); $params['sign'] = $this->getPaySign($params, $signType); $result = Tools::xml2arr(Tools::post($url, Tools::arr2xml($params), $option)); if ($result['return_code'] !== 'SUCCESS') { throw new InvalidResponseException($result['return_msg'], '0'); } return $result; } }