From 6491a874aa1ea968799770092a8ccfa1b067730d Mon Sep 17 00:00:00 2001 From: Anyon Date: Wed, 31 Jan 2018 15:25:18 +0800 Subject: [PATCH] =?UTF-8?q?[=E6=9B=B4=E6=96=B0]=E4=BF=AE=E6=94=B9=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E5=91=BD=E5=90=8D=E7=A9=BA=E9=97=B4=20[=E6=9B=B4?= =?UTF-8?q?=E6=96=B0]=E5=A2=9E=E5=8A=A0=E5=BE=AE=E4=BF=A1=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WeChat/Pay.php | 212 ++++++++++++++++++ Wechat/Contracts/Config.php | 14 ++ Wechat/Contracts/Tools.php | 16 ++ Wechat/Contracts/Wechat.php | 186 --------------- Wechat/Custom.php | 10 +- .../Exceptions/InvalidArgumentException.php | 4 +- Wechat/Exceptions/InvalidDecryptException.php | 4 +- .../Exceptions/InvalidResponseException.php | 4 +- Wechat/Exceptions/LocalCacheException.php | 4 +- Wechat/Media.php | 12 +- Wechat/Menu.php | 8 +- Wechat/Product.php | 8 +- Wechat/Qrcode.php | 8 +- Wechat/Receive.php | 6 +- Wechat/Scan.php | 8 +- Wechat/Script.php | 16 +- Wechat/Shake.php | 10 +- Wechat/Tags.php | 8 +- Wechat/Template.php | 8 +- Wechat/User.php | 8 +- Wechat/Wifi.php | 8 +- 21 files changed, 309 insertions(+), 253 deletions(-) create mode 100644 WeChat/Pay.php delete mode 100644 Wechat/Contracts/Wechat.php diff --git a/WeChat/Pay.php b/WeChat/Pay.php new file mode 100644 index 0000000..6dafc29 --- /dev/null +++ b/WeChat/Pay.php @@ -0,0 +1,212 @@ +config = new Config($options); + $this->params = new Config([ + 'appid' => $this->config->get('appid'), + 'mch_id' => $this->config->get('mch_id'), + 'nonce_str' => Tools::createNoncestr(), + ]); + } + + /** + * 统一下单 + * @param array $options + * @return array + */ + public function order(array $options) + { + $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; + return $this->callPostApi($url, $options); + } + + /** + * 查询订单 + * @param array $options + * @return array + */ + 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 + */ + public function close($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 + */ + public function refund(array $options) + { + $url = 'https://api.mch.weixin.qq.com/secapi/pay/refund'; + return $this->callPostApi($url, $options, true); + } + + /** + * 查询退款 + * @param array $options + * @return array + */ + public function queryRefund(array $options) + { + $url = 'https://api.mch.weixin.qq.com/pay/refundquery'; + return $this->callPostApi($url, $options); + } + + /** + * 交易保障 + * @param array $options + * @return array + */ + 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 + */ + 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 + */ + 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 + */ + public function bill(array $options) + { + $url = 'https://api.mch.weixin.qq.com/pay/downloadbill'; + return $this->callPostApi($url, $options); + } + + + /** + * 拉取订单评价数据 + * @param array $options + * @return array + */ + public function billCommtent(array $options) + { + $url = 'https://api.mch.weixin.qq.com/billcommentsp/batchquerycomment'; + return $this->callPostApi($url, $options, true); + } + + /** + * 获取微信支付通知 + * @return array + * @throws InvalidResponseException + */ + public function getNotify() + { + $data = Tools::xml2arr(file_get_contents('php://input')); + if (!empty($data['sign'])) { + if (Tools::getPaySign($data, $this->config->get('mch_key')) === $data['sign']) { + return $data; + } + } + throw new InvalidResponseException('Invalid Notify.', '0'); + } + + /** + * 以Post请求接口 + * @param string $url 请求 + * @param array $data 接口参数 + * @param bool $isCert 是否需要使用双向证书 + * @return array + */ + public function callPostApi($url, array $data, $isCert = false) + { + $option = []; + if ($isCert) { + foreach (['ssl_cer', 'ssl_key'] as $key) { + if (empty($options['ssl_cer'])) { + 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); + $params['sign_type'] = 'HMAC-SHA256'; + $params['sign'] = Tools::getPaySign($params, $this->config->get('mch_key')); + return Tools::xml2arr(Tools::post($url, Tools::arr2xml($params), $option)); + } +} \ No newline at end of file diff --git a/Wechat/Contracts/Config.php b/Wechat/Contracts/Config.php index de5a3cd..6e73ce7 100644 --- a/Wechat/Contracts/Config.php +++ b/Wechat/Contracts/Config.php @@ -58,6 +58,20 @@ class Config implements ArrayAccess return $this->offsetGet($offset); } + /** + * 合并数据到对象 + * @param array $data 需要合并的数据 + * @param bool $append 是否追加数据 + * @return array + */ + public function merge(array $data, $append = false) + { + if ($append) { + return $this->config = array_merge($this->config, $data); + } + return array_merge($this->config, $data); + } + /** * 设置配置项值 * @param string $offset diff --git a/Wechat/Contracts/Tools.php b/Wechat/Contracts/Tools.php index 08ead4b..e8766fe 100644 --- a/Wechat/Contracts/Tools.php +++ b/Wechat/Contracts/Tools.php @@ -66,6 +66,22 @@ class Tools return $method(join('&', $params)); } + /** + * 生成支付签名 + * @param array $data + * @param string $mchKey 商户密钥 + * @return string + */ + public static function getPaySign(array $data, $mchKey) + { + ksort($data); + $string = ""; + foreach ($data as $key => $value) { + $string .= "{$key}={$value}&"; + } + return strtoupper(hash_hmac('SHA256', "{$string}key={$mchKey}", $mchKey)); + } + /** * 根据文件后缀获取文件MINE * @param array $ext 文件后缀 diff --git a/Wechat/Contracts/Wechat.php b/Wechat/Contracts/Wechat.php deleted file mode 100644 index e619315..0000000 --- a/Wechat/Contracts/Wechat.php +++ /dev/null @@ -1,186 +0,0 @@ -config = new Config($options); - } - - /** - * 获取访问accessToken - * @return string - * @throws \Wechat\Exceptions\InvalidResponseException - * @throws \Wechat\Exceptions\LocalCacheException - */ - public function getAccesstoken() - { - if (!empty($this->access_token)) { - return $this->access_token; - } - $cacheKey = $this->config->get('appid') . '_accesstoken'; - $this->access_token = Tools::getCache($cacheKey); - if (!empty($this->access_token)) { - return $this->access_token; - } - list($appid, $secret) = [$this->config->get('appid'), $this->config->get('appsecret')]; - $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appid}&secret={$secret}"; - $result = Tools::json2arr(Tools::get($url)); - if (!empty($result['access_token'])) { - Tools::setCache($cacheKey, $result['access_token'], 6000); - } - return $result['access_token']; - } - - /** - * 清理删除accessToken - * @return bool - */ - public function delAccessToken() - { - $this->access_token = ''; - return Tools::delCache($this->config->get('appid') . '_accesstoken'); - } - - - /** - * 以GET获取接口数据并转为数组 - * @param string $url 接口地址 - * @return array - */ - protected function httpGetForJson($url) - { - try { - return Tools::json2arr(Tools::get($url)); - } catch (InvalidResponseException $e) { - if (!$this->isTry && in_array($e->getCode(), ['40014', '40001', '41001', '42001'])) { - $this->delAccessToken(); - $this->isTry = true; - return call_user_func_array([$this, $this->currentMethod['method']], $this->currentMethod['arguments']); - } - } - } - - /** - * 以POST获取接口数据并转为数组 - * @param string $url 接口地址 - * @param array $data 请求数据 - * @param bool $buildToJson - * @return array - */ - protected function httpPostForJson($url, array $data, $buildToJson = true) - { - try { - return Tools::json2arr(Tools::post($url, $buildToJson ? Tools::arr2json($data) : $data)); - } catch (InvalidResponseException $e) { - if (!$this->isTry && in_array($e->getCode(), ['40014', '40001', '41001', '42001'])) { - $this->delAccessToken(); - $this->isTry = true; - return call_user_func_array([$this, $this->currentMethod['method']], $this->currentMethod['arguments']); - } - } - } - - /** - * 注册当前请求接口 - * @param string $url 接口地址 - * @param string $method 当前接口方法 - * @param array $arguments 请求参数 - * @return mixed - * @throws \Wechat\Exceptions\InvalidResponseException - * @throws \Wechat\Exceptions\LocalCacheException - */ - protected function registerApi(&$url, $method, $arguments = []) - { - $this->currentMethod = ['method' => $method, 'arguments' => $arguments]; - if (empty($this->access_token)) { - $this->access_token = $this->getAccesstoken(); - } - return $url = str_replace('ACCESS_TOKEN', $this->access_token, $url); - } - - /** - * 接口通用POST请求方法 - * @param string $url 接口URL - * @param array $data POST提交接口参数 - * @param bool $isBuildJson - * @return array - * @throws InvalidResponseException - * @throws \Wechat\Exceptions\LocalCacheException - */ - public function callPostApi($url, array $data, $isBuildJson = true) - { - $this->registerApi($url, __FUNCTION__, func_get_args()); - return $this->httpPostForJson($url, $data, $isBuildJson); - } - - /** - * 接口通用GET请求方法 - * @param string $url 接口URL - * @return array - * @throws InvalidResponseException - * @throws \Wechat\Exceptions\LocalCacheException - */ - public function callGetApi($url) - { - $this->registerApi($url, __FUNCTION__, func_get_args()); - return $this->httpGetForJson($url); - } - -} \ No newline at end of file diff --git a/Wechat/Custom.php b/Wechat/Custom.php index c47c330..4503378 100644 --- a/Wechat/Custom.php +++ b/Wechat/Custom.php @@ -12,16 +12,16 @@ // | github开源项目:https://github.com/zoujingli/WeChatDeveloper // +---------------------------------------------------------------------- -namespace Wechat; +namespace WeChat; -use Wechat\Contracts\Wechat; +use WeChat\Contracts\WePay; /** * 客服消息处理 * Class Custom - * @package Wechat + * @package WeChat */ -class Custom extends Wechat +class Custom extends WePay { /** * 添加客服帐号 @@ -155,7 +155,7 @@ class Custom extends Wechat public function massDelete($msg_id, $article_idx = null) { $data = ['msg_id' => $msg_id]; - is_null($article_idx) || $article_idx; + is_null($article_idx) || $data['article_idx'] = $article_idx; $url = "https://api.weixin.qq.com/cgi-bin/message/mass/delete?access_token=ACCESS_TOKEN"; $this->registerApi($url, __FUNCTION__, func_get_args()); return $this->httpPostForJson($url, $data); diff --git a/Wechat/Exceptions/InvalidArgumentException.php b/Wechat/Exceptions/InvalidArgumentException.php index 1701e12..e9740c8 100644 --- a/Wechat/Exceptions/InvalidArgumentException.php +++ b/Wechat/Exceptions/InvalidArgumentException.php @@ -12,12 +12,12 @@ // | github开源项目:https://github.com/zoujingli/WeChatDeveloper // +---------------------------------------------------------------------- -namespace Wechat\Exceptions; +namespace WeChat\Exceptions; /** * 参数异常 * Class InvalidArgumentException - * @package Wechat + * @package WeChat */ class InvalidArgumentException extends \InvalidArgumentException { diff --git a/Wechat/Exceptions/InvalidDecryptException.php b/Wechat/Exceptions/InvalidDecryptException.php index 6596a9e..bdbe31c 100644 --- a/Wechat/Exceptions/InvalidDecryptException.php +++ b/Wechat/Exceptions/InvalidDecryptException.php @@ -12,12 +12,12 @@ // | github开源项目:https://github.com/zoujingli/WeChatDeveloper // +---------------------------------------------------------------------- -namespace Wechat\Exceptions; +namespace WeChat\Exceptions; /** * 返回异常 * Class InvalidResponseException - * @package Wechat + * @package WeChat */ class InvalidDecryptException extends \Exception { diff --git a/Wechat/Exceptions/InvalidResponseException.php b/Wechat/Exceptions/InvalidResponseException.php index 017b21c..d5a2c12 100644 --- a/Wechat/Exceptions/InvalidResponseException.php +++ b/Wechat/Exceptions/InvalidResponseException.php @@ -12,12 +12,12 @@ // | github开源项目:https://github.com/zoujingli/WeChatDeveloper // +---------------------------------------------------------------------- -namespace Wechat\Exceptions; +namespace WeChat\Exceptions; /** * 返回异常 * Class InvalidResponseException - * @package Wechat + * @package WeChat */ class InvalidResponseException extends \Exception { diff --git a/Wechat/Exceptions/LocalCacheException.php b/Wechat/Exceptions/LocalCacheException.php index 4f112fa..2814768 100644 --- a/Wechat/Exceptions/LocalCacheException.php +++ b/Wechat/Exceptions/LocalCacheException.php @@ -12,12 +12,12 @@ // | github开源项目:https://github.com/zoujingli/WeChatDeveloper // +---------------------------------------------------------------------- -namespace Wechat\Exceptions; +namespace WeChat\Exceptions; /*** * 本地缓存异常 * Class LocalCacheException - * @package Wechat + * @package WeChat */ class LocalCacheException extends \Exception { diff --git a/Wechat/Media.php b/Wechat/Media.php index 0eb2a3b..7b1e7e9 100644 --- a/Wechat/Media.php +++ b/Wechat/Media.php @@ -12,18 +12,18 @@ // | github开源项目:https://github.com/zoujingli/WeChatDeveloper // +---------------------------------------------------------------------- -namespace Wechat; +namespace WeChat; -use Wechat\Contracts\Tools; -use Wechat\Contracts\Wechat; -use Wechat\Exceptions\InvalidResponseException; +use WeChat\Contracts\Tools; +use WeChat\Contracts\WePay; +use WeChat\Exceptions\InvalidResponseException; /** * 微信素材管理 * Class Media - * @package Wechat + * @package WeChat */ -class Media extends Wechat +class Media extends WePay { /** * 新增临时素材 diff --git a/Wechat/Menu.php b/Wechat/Menu.php index 09f9152..993b8d3 100644 --- a/Wechat/Menu.php +++ b/Wechat/Menu.php @@ -12,16 +12,16 @@ // | github开源项目:https://github.com/zoujingli/WeChatDeveloper // +---------------------------------------------------------------------- -namespace Wechat; +namespace WeChat; -use Wechat\Contracts\Wechat; +use WeChat\Contracts\WePay; /** * 微信菜单管理 * Class Menu - * @package Wechat + * @package WeChat */ -class Menu extends Wechat +class Menu extends WePay { /** diff --git a/Wechat/Product.php b/Wechat/Product.php index df88536..e912f21 100644 --- a/Wechat/Product.php +++ b/Wechat/Product.php @@ -12,17 +12,17 @@ // | github开源项目:https://github.com/zoujingli/WeChatDeveloper // +---------------------------------------------------------------------- -namespace Wechat; +namespace WeChat; -use Wechat\Contracts\Wechat; +use WeChat\Contracts\WePay; /** * 商店管理 * Class Product - * @package Wechat + * @package WeChat */ -class Product extends Wechat +class Product extends WePay { /** * 提交审核/取消发布商品 diff --git a/Wechat/Qrcode.php b/Wechat/Qrcode.php index 33b65a3..aff5d39 100644 --- a/Wechat/Qrcode.php +++ b/Wechat/Qrcode.php @@ -12,16 +12,16 @@ // | github开源项目:https://github.com/zoujingli/WeChatDeveloper // +---------------------------------------------------------------------- -namespace Wechat; +namespace WeChat; -use Wechat\Contracts\Wechat; +use WeChat\Contracts\WePay; /** * 二维码管理 * Class Qrcode - * @package Wechat + * @package WeChat */ -class Qrcode extends Wechat +class Qrcode extends WePay { /** diff --git a/Wechat/Receive.php b/Wechat/Receive.php index 44ca865..1cb78cf 100644 --- a/Wechat/Receive.php +++ b/Wechat/Receive.php @@ -12,14 +12,14 @@ // | github开源项目:https://github.com/zoujingli/WeChatDeveloper // +---------------------------------------------------------------------- -namespace Wechat; +namespace WeChat; -use Wechat\Contracts\Request; +use WeChat\Contracts\Request; /** * 公众号推送管理 * Class Receive - * @package Wechat + * @package WeChat */ class Receive extends Request { diff --git a/Wechat/Scan.php b/Wechat/Scan.php index 21a23fe..54d5244 100644 --- a/Wechat/Scan.php +++ b/Wechat/Scan.php @@ -12,16 +12,16 @@ // | github开源项目:https://github.com/zoujingli/WeChatDeveloper // +---------------------------------------------------------------------- -namespace Wechat; +namespace WeChat; -use Wechat\Contracts\Wechat; +use WeChat\Contracts\WePay; /** * 扫一扫接入管理 * Class Scan - * @package Wechat + * @package WeChat */ -class Scan extends Wechat +class Scan extends WePay { /** * 获取商户信息 diff --git a/Wechat/Script.php b/Wechat/Script.php index 875464b..7a96dde 100644 --- a/Wechat/Script.php +++ b/Wechat/Script.php @@ -12,18 +12,18 @@ // | github开源项目:https://github.com/zoujingli/WeChatDeveloper // +---------------------------------------------------------------------- -namespace Wechat; +namespace WeChat; -use Wechat\Contracts\Tools; -use Wechat\Contracts\Wechat; -use Wechat\Exceptions\InvalidResponseException; +use WeChat\Contracts\Tools; +use WeChat\Contracts\WePay; +use WeChat\Exceptions\InvalidResponseException; /** * 微信前端支持 * Class Script - * @package Wechat + * @package WeChat */ -class Script extends Wechat +class Script extends WePay { /** @@ -35,7 +35,7 @@ class Script extends Wechat public function delTicket($type = 'jsapi', $appid = null) { is_null($appid) && $appid = $this->config->get('appid'); - $cache_name = "wechat_{$type}_ticket_{$appid}"; + $cache_name = "WeChat_{$type}_ticket_{$appid}"; Tools::delCache($cache_name); } @@ -50,7 +50,7 @@ class Script extends Wechat public function getTicket($type = 'jsapi', $appid = null) { is_null($appid) && $appid = $this->config->get('appid'); - $cache_name = "wechat_{$type}_ticket_{$appid}"; + $cache_name = "WeChat_{$type}_ticket_{$appid}"; $ticket = Tools::getCache($cache_name); if (empty($ticket)) { $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type={$type}"; diff --git a/Wechat/Shake.php b/Wechat/Shake.php index 5f34791..6d8b2e4 100644 --- a/Wechat/Shake.php +++ b/Wechat/Shake.php @@ -12,18 +12,18 @@ // | github开源项目:https://github.com/zoujingli/WeChatDeveloper // +---------------------------------------------------------------------- -namespace Wechat; +namespace WeChat; -use Wechat\Contracts\Tools; -use Wechat\Contracts\Wechat; +use WeChat\Contracts\Tools; +use WeChat\Contracts\WePay; /** * 揺一揺周边 * Class Shake - * @package Wechat + * @package WeChat */ -class Shake extends Wechat +class Shake extends WePay { /** * 申请开通功能 diff --git a/Wechat/Tags.php b/Wechat/Tags.php index 829beca..0301798 100644 --- a/Wechat/Tags.php +++ b/Wechat/Tags.php @@ -12,16 +12,16 @@ // | github开源项目:https://github.com/zoujingli/WeChatDeveloper // +---------------------------------------------------------------------- -namespace Wechat; +namespace WeChat; -use Wechat\Contracts\Wechat; +use WeChat\Contracts\WePay; /** * 用户标签管理 * Class Tags - * @package Wechat + * @package WeChat */ -class Tags extends Wechat +class Tags extends WePay { /** * 获取粉丝标签列表 diff --git a/Wechat/Template.php b/Wechat/Template.php index 4bebd8e..7b2ba2a 100644 --- a/Wechat/Template.php +++ b/Wechat/Template.php @@ -12,16 +12,16 @@ // | github开源项目:https://github.com/zoujingli/WeChatDeveloper // +---------------------------------------------------------------------- -namespace Wechat; +namespace WeChat; -use Wechat\Contracts\Wechat; +use WeChat\Contracts\WePay; /** * 模板消息 * Class Template - * @package Wechat + * @package WeChat */ -class Template extends Wechat +class Template extends WePay { /** * 设置所属行业 diff --git a/Wechat/User.php b/Wechat/User.php index b55c384..6e89494 100644 --- a/Wechat/User.php +++ b/Wechat/User.php @@ -12,16 +12,16 @@ // | github开源项目:https://github.com/zoujingli/WeChatDeveloper // +---------------------------------------------------------------------- -namespace Wechat; +namespace WeChat; -use Wechat\Contracts\Wechat; +use WeChat\Contracts\WePay; /** * 微信粉丝管理 * Class User - * @package Wechat + * @package WeChat */ -class User extends Wechat +class User extends WePay { /** diff --git a/Wechat/Wifi.php b/Wechat/Wifi.php index 4b23ed5..0b29b81 100644 --- a/Wechat/Wifi.php +++ b/Wechat/Wifi.php @@ -12,17 +12,17 @@ // | github开源项目:https://github.com/zoujingli/WeChatDeveloper // +---------------------------------------------------------------------- -namespace Wechat; +namespace WeChat; -use Wechat\Contracts\Wechat; +use WeChat\Contracts\WePay; /** * 门店 WIFI 管理 * Class Wifi - * @package Wechat + * @package WeChat */ -class Wifi extends Wechat +class Wifi extends WePay { /**