[更新]修改项目命名空间

[更新]增加微信支付支持
This commit is contained in:
Anyon 2018-01-31 15:25:18 +08:00
parent cc0c53d93d
commit 6491a874aa
21 changed files with 309 additions and 253 deletions

212
WeChat/Pay.php Normal file
View File

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

View File

@ -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

View File

@ -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 文件后缀

View File

@ -1,186 +0,0 @@
<?php
// +----------------------------------------------------------------------
// | WeChatDeveloper
// +----------------------------------------------------------------------
// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://think.ctolog.com
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | github开源项目https://github.com/zoujingli/WeChatDeveloper
// +----------------------------------------------------------------------
namespace Wechat\Contracts;
use Wechat\Exceptions\InvalidArgumentException;
use Wechat\Exceptions\InvalidResponseException;
/**
* Class Wechat
* @package Wechat\Contracts
*/
class Wechat
{
/**
* 当前微信配置
* @var Config
*/
public $config;
/**
* 访问AccessToken
* @var string
*/
public $access_token = '';
/**
* 当前请求方法参数
* @var array
*/
private $currentMethod = [];
/**
* 当前模式
* @var bool
*/
private $isTry = false;
/**
* Wechat constructor.
* @param array $options
*/
public function __construct(array $options)
{
if (empty($options['appid'])) {
throw new InvalidArgumentException("Missing Config -- [appid]");
}
if (empty($options['appsecret'])) {
throw new InvalidArgumentException("Missing Config -- [appsecret]");
}
$this->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);
}
}

View File

@ -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);

View File

@ -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
{

View File

@ -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
{

View File

@ -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
{

View File

@ -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
{

View File

@ -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
{
/**
* 新增临时素材

View File

@ -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
{
/**

View File

@ -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
{
/**
* 提交审核/取消发布商品

View File

@ -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
{
/**

View File

@ -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
{

View File

@ -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
{
/**
* 获取商户信息

View File

@ -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}";

View File

@ -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
{
/**
* 申请开通功能

View File

@ -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
{
/**
* 获取粉丝标签列表

View File

@ -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
{
/**
* 设置所属行业

View File

@ -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
{
/**

View File

@ -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
{
/**