2018-05-09 12:22:21 +08:00

319 lines
9.6 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
// +----------------------------------------------------------------------
// | WeChatDeveloper
// +----------------------------------------------------------------------
// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://think.ctolog.com
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | github开源项目https://github.com/zoujingli/WeChatDeveloper
// +----------------------------------------------------------------------
namespace WeChat;
use WeChat\Contracts\DataArray;
use WeChat\Contracts\Tools;
use WeChat\Exceptions\InvalidArgumentException;
use WeChat\Exceptions\InvalidResponseException;
/**
* 微信支付商户
* Class Pay
* @package WeChat\Contracts
*/
class Pay
{
/**
* 商户配置
* @var DataArray
*/
protected $config;
/**
* 当前请求数据
* @var DataArray
*/
protected $params;
/**
* WeChat constructor.
* @param array $options
*/
public function __construct(array $options)
{
if (empty($options['appid'])) {
throw new InvalidArgumentException("Missing Config -- [appid]");
}
if (empty($options['mch_id'])) {
throw new InvalidArgumentException("Missing Config -- [mch_id]");
}
if (empty($options['mch_key'])) {
throw new InvalidArgumentException("Missing Config -- [mch_key]");
}
if (!empty($options['cache_path'])) {
Tools::$cache_path = $options['cache_path'];
}
$this->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)
{
$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) {
foreach (['ssl_cer', 'ssl_key'] as $key) {
if (empty($option[$key])) {
throw new InvalidArgumentException("Missing Config -- [{$key}]", '0');
}
}
$option['ssl_cer'] = $this->config->get('ssl_cer');
$option['ssl_key'] = $this->config->get('ssl_key');
}
$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;
}
}