<?php
namespace
common\services\WechatPay;
class
WechatAppPay
extends
WechatPayBase
{
public
$package
= [];
public
$notify
= [];
protected
$config
= [];
protected
$file
;
protected
$accessToken
;
const
ACCESS_TOKEN_URL =
'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s'
;
const
POST_ORDER_URL =
'https://api.weixin.qq.com/pay/genprepay?access_token=%s'
;
public
function
__construct()
{
$this
->file = __DIR__ .
'/payAccessToken.txt'
;
}
public
function
createAppPayData()
{
$this
->generateConfig();
$prepayid
=
$this
->getPrepayid();
try
{
$array
= [
'appid'
=>
$this
->appid,
'appkey'
=>
$this
->paySignkey,
'noncestr'
=>
$this
->getRandomStr(),
'package'
=>
'Sign=WXPay'
,
'partnerid'
=>
$this
->partnerId,
'prepayid'
=>
$prepayid
,
'timestamp'
=> (string)time(),
];
$array
[
'sign'
] =
$this
->sha1Sign(
$array
);
unset(
$array
[
'appkey'
]);
}
catch
(\Exception
$e
) {
throw
new
\Exception(
$e
->getMessage());
}
return
$array
;
}
public
function
verifyNotify()
{
try
{
$staySignStr
=
$this
->notify;
unset(
$staySignStr
[
'sign'
]);
$sign
=
$this
->signData(
$staySignStr
);
return
$this
->notify[
'sign'
] ===
$sign
;
}
catch
(\Exception
$e
) {
throw
new
\Exception(
$e
->getMessage());
}
}
public
function
__set(
$name
,
$value
)
{
$this
->
$name
=
$value
;
}
public
function
setAccessToken()
{
try
{
if
(!
file_exists
(
$this
->file) || !
is_file
(
$this
->file)) {
$f
=
fopen
(
$this
->file,
'a'
);
fclose(
$f
);
}
$content
=
file_get_contents
(
$this
->file);
if
(!
empty
(
$content
)) {
$info
= json_decode(
$content
, true);
if
( time() -
$info
[
'getTime'
] < 7150 ) {
$this
->accessToken =
$info
[
'accessToken'
];
return
true;
}
}
$this
->outputAccessTokenToFile();
}
catch
(\Exception
$e
) {
throw
new
\Exception(
$e
->getMessage());
}
return
true;
}
protected
function
outputAccessTokenToFile()
{
try
{
$f
=
fopen
(
$this
->file,
'wb'
);
$token
= [
'accessToken'
=>
$this
->getAccessToken(),
'getTime'
=> time(),
];
flock
(
$f
, LOCK_EX);
fwrite(
$f
, json_encode(
$token
));
flock
(
$f
, LOCK_UN);
fclose(
$f
);
$this
->accessToken =
$token
[
'accessToken'
];
}
catch
(\Exception
$e
) {
throw
new
\Exception(
$e
->getMessage());
}
return
true;
}
protected
function
getAccessToken()
{
$url
= sprintf(self::ACCESS_TOKEN_URL,
$this
->appid,
$this
->appSecret);
$result
= json_decode(
$this
->getUrl(
$url
), true );
if
(isset(
$result
[
'errcode'
])) {
throw
new
\Exception(
"get access token failed:{$result['errmsg']}"
);
}
return
$result
[
'access_token'
];
}
protected
function
getPrepayid()
{
$data
= json_encode(
$this
->config);
$url
= sprintf(self::POST_ORDER_URL,
$this
->accessToken);
$result
= json_decode(
$this
->postUrl(
$url
,
$data
), true );
if
( isset(
$result
[
'errcode'
]) &&
$result
[
'errcode'
] != 0 ) {
throw
new
\Exception(
$result
[
'errmsg'
]);
}
if
( !isset(
$result
[
'prepayid'
]) ) {
throw
new
\Exception(
'get prepayid failed, url request error.'
);
}
return
$result
[
'prepayid'
];
}
protected
function
generateConfig()
{
try
{
$this
->config = [
'appid'
=>
$this
->appid,
'traceid'
=>
$this
->traceid,
'noncestr'
=>
$this
->getRandomStr(),
'timestamp'
=> time(),
'package'
=>
$this
->generatePackage(),
'sign_method'
=>
$this
->sign_method,
];
$this
->config[
'app_signature'
] =
$this
->generateSign();
}
catch
(\Exception
$e
) {
throw
new
\Exception(
$e
->getMessage());
}
}
protected
function
generatePackage()
{
$this
->package[
'sign'
] =
$this
->signData(
$this
->package);
return
http_build_query(
$this
->package,
''
,
'&'
, PHP_QUERY_RFC3986);
}
protected
function
generateSign()
{
$signArray
= [
'appid'
=>
$this
->appid,
'appkey'
=>
$this
->paySignkey,
'noncestr'
=>
$this
->config[
'noncestr'
],
'package'
=>
$this
->config[
'package'
],
'timestamp'
=>
$this
->config[
'timestamp'
],
'traceid'
=>
$this
->traceid,
];
return
$this
->sha1Sign(
$signArray
);
}
protected
function
signData(
$data
)
{
ksort(
$data
);
$str
=
$this
->arrayToString(
$data
);
$str
.=
"&key={$this->partnerKey}"
;
return
strtoupper
(
$this
->signMd5(
$str
) );
}
protected
function
sha1Sign(
$arr
)
{
ksort(
$arr
);
return
sha1(
$this
->arrayToString(
$arr
) );
}
}