|
@@ -2,9 +2,8 @@
|
|
|
|
|
|
namespace App\Helper;
|
|
namespace App\Helper;
|
|
|
|
|
|
-use App\Helper\Bytedance\ByteDanceAPI;
|
|
|
|
-use App\Models\Pay;
|
|
|
|
-use Carbon\Carbon;
|
|
|
|
|
|
+use App\Helper\UniPlatform\BaseAPI;
|
|
|
|
+use App\Helper\UniPlatform\BaseUniPlatform;
|
|
use GuzzleHttp\Client;
|
|
use GuzzleHttp\Client;
|
|
use GuzzleHttp\Exception\GuzzleException;
|
|
use GuzzleHttp\Exception\GuzzleException;
|
|
|
|
|
|
@@ -21,107 +20,21 @@ use GuzzleHttp\Exception\GuzzleException;
|
|
* @property-read string $noticeUrl
|
|
* @property-read string $noticeUrl
|
|
* @property-read string $validTimestamp
|
|
* @property-read string $validTimestamp
|
|
*/
|
|
*/
|
|
-class ByteDance
|
|
|
|
|
|
+class ByteDance extends BaseUniPlatform
|
|
{
|
|
{
|
|
- private $appId = null;
|
|
|
|
- private $secret = null;
|
|
|
|
- private $slat = null;
|
|
|
|
- private $token = null;
|
|
|
|
|
|
|
|
-
|
|
|
|
- private $accessTokenFile = null;
|
|
|
|
- private $accessToken = null;
|
|
|
|
- private $noticeUrl = null;
|
|
|
|
- //订单过期时间(秒);
|
|
|
|
- private $validTimestamp = 24 * 60 * 60;
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * @param array $config
|
|
|
|
- * @return $this
|
|
|
|
- */
|
|
|
|
- public function factory($config = [])
|
|
|
|
- {
|
|
|
|
- $this->appId = $config['app_id'];
|
|
|
|
- $this->secret = $config['app_secret'];
|
|
|
|
- $this->slat = $config['slat'];
|
|
|
|
- $this->token = $config['token'];
|
|
|
|
- $this->accessTokenFile = storage_path('app/bytedance/bytedance_access_token.json');
|
|
|
|
- $this->accessToken = $this->checkAccessToken();
|
|
|
|
-
|
|
|
|
- $this->noticeUrl = env('APP_URL').'/api/pay/bytedance/notify';
|
|
|
|
- return $this;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * @param string $code
|
|
|
|
- * @return array|mixed
|
|
|
|
- * @throws \Exception
|
|
|
|
- */
|
|
|
|
- public function login($code = '')
|
|
|
|
|
|
+ public function __construct(BaseAPI $api)
|
|
{
|
|
{
|
|
- return $this->post(ByteDanceAPI::LOGIN, [
|
|
|
|
- 'appid' => $this->appId,
|
|
|
|
- 'secret' => $this->secret,
|
|
|
|
- 'code' => $code,
|
|
|
|
- ]);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * @param string $sessionKey
|
|
|
|
- * @param string $iv
|
|
|
|
- * @param string $encrypted
|
|
|
|
- * @return array
|
|
|
|
- * @throws \Exception
|
|
|
|
- */
|
|
|
|
- public function decryptData(string $sessionKey, string $iv, string $encrypted): array
|
|
|
|
- {
|
|
|
|
- $decrypted = openssl_decrypt(
|
|
|
|
- base64_decode($encrypted,true),
|
|
|
|
- 'AES-128-CBC',
|
|
|
|
- base64_decode($sessionKey),
|
|
|
|
- OPENSSL_RAW_DATA,
|
|
|
|
- base64_decode($iv)
|
|
|
|
- );
|
|
|
|
- $decrypted = json_decode($decrypted,true);
|
|
|
|
- if(empty($decrypted)){
|
|
|
|
- throw new \Exception('解密数据错误');
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return $decrypted;
|
|
|
|
|
|
+ $this->API = $api;
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * 校验access token 是否过期
|
|
|
|
- * @return mixed
|
|
|
|
- */
|
|
|
|
- private function checkAccessToken() : string
|
|
|
|
- {
|
|
|
|
- try {
|
|
|
|
- $dir = storage_path('app/bytedance');
|
|
|
|
- if (!is_dir($dir)) mkdir($dir, 0755);
|
|
|
|
- if (!is_file($this->accessTokenFile)) touch($this->accessTokenFile);
|
|
|
|
-
|
|
|
|
- $accessToken = file_get_contents($this->accessTokenFile);
|
|
|
|
- $accessToken = $accessToken ? json_decode($accessToken,true) : null;
|
|
|
|
- if (empty($accessToken) || $accessToken['expires_at'] < time()) {
|
|
|
|
- $accessToken = $this->getAccessToken();
|
|
|
|
- }else{
|
|
|
|
- $accessToken = $accessToken['access_token'];
|
|
|
|
- }
|
|
|
|
- return $accessToken;
|
|
|
|
- } catch (\Exception $e) {
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* 获取 access token
|
|
* 获取 access token
|
|
* @throws \Exception
|
|
* @throws \Exception
|
|
*/
|
|
*/
|
|
- private function getAccessToken() : string
|
|
|
|
|
|
+ protected function getAccessToken() : string
|
|
{
|
|
{
|
|
- $res = $this->post(ByteDanceAPI::ACCESS_TOKEN, [
|
|
|
|
|
|
+ $res = $this->post($this->API::ACCESS_TOKEN, [
|
|
'grant_type' => 'client_credential',
|
|
'grant_type' => 'client_credential',
|
|
'appid' => $this->appId,
|
|
'appid' => $this->appId,
|
|
'secret' => $this->secret,
|
|
'secret' => $this->secret,
|
|
@@ -138,44 +51,13 @@ class ByteDance
|
|
return $res['access_token'];
|
|
return $res['access_token'];
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * 接口请求
|
|
|
|
- *
|
|
|
|
- * @param string $uri
|
|
|
|
- * @param array $data
|
|
|
|
- * @return array|mixed
|
|
|
|
- * @throws \Exception
|
|
|
|
- */
|
|
|
|
- private function post($uri = '', $data = []) : array
|
|
|
|
- {
|
|
|
|
- try {
|
|
|
|
- $client = new Client();
|
|
|
|
- $res = $client->post($uri, [
|
|
|
|
- 'verify' => false,
|
|
|
|
- 'headers' => ['Content-Type' => 'application/json'],
|
|
|
|
- 'body' => json_encode($data)
|
|
|
|
- ]);
|
|
|
|
- $stringBody = (string)$res->getBody();
|
|
|
|
- $res = json_decode($stringBody, true);
|
|
|
|
-
|
|
|
|
- if(!empty($res['err_no'])){
|
|
|
|
- throw new \Exception("请求字节跳动API接口错误,错误码:{$res['err_no']},错误信息:{$res['err_tips']}");
|
|
|
|
- }
|
|
|
|
- return $res['data'];
|
|
|
|
- } catch (GuzzleException $e) {
|
|
|
|
- \Log::error($e->getMessage());
|
|
|
|
- throw new \Exception($e->getMessage());
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* @param $outOrderNo
|
|
* @param $outOrderNo
|
|
* @param $totalAmount
|
|
* @param $totalAmount
|
|
* @return array|mixed
|
|
* @return array|mixed
|
|
* @throws \Exception
|
|
* @throws \Exception
|
|
*/
|
|
*/
|
|
- public function createOrder($outOrderNo, $totalAmount)
|
|
|
|
|
|
+ public function createOrder($outOrderNo, $totalAmount): array
|
|
{
|
|
{
|
|
$data = [
|
|
$data = [
|
|
'app_id' => $this->appId,
|
|
'app_id' => $this->appId,
|
|
@@ -191,7 +73,7 @@ class ByteDance
|
|
$data['sign'] = $this->getSign($data);
|
|
$data['sign'] = $this->getSign($data);
|
|
|
|
|
|
return $this->post(
|
|
return $this->post(
|
|
- ByteDanceAPI::CREATE_ORDER,
|
|
|
|
|
|
+ $this->API::CREATE_ORDER,
|
|
$data
|
|
$data
|
|
);
|
|
);
|
|
}
|
|
}
|
|
@@ -245,56 +127,58 @@ class ByteDance
|
|
return sha1(trim(implode('', $filtered)));
|
|
return sha1(trim(implode('', $filtered)));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * @param \Closure $closure
|
|
|
|
- * @return \Illuminate\Http\JsonResponse
|
|
|
|
|
|
+ * @param string $code
|
|
|
|
+ * @return array|mixed
|
|
* @throws \Exception
|
|
* @throws \Exception
|
|
*/
|
|
*/
|
|
- public function payNotify(\Closure $closure)
|
|
|
|
|
|
+ public function login($code = ''): array
|
|
{
|
|
{
|
|
- call_user_func($closure, $this->getNoticeData());
|
|
|
|
-
|
|
|
|
- return response()->json($data);
|
|
|
|
-
|
|
|
|
- if ($notify['msg_signature'] !== $this->getNotifySign($notify)) {
|
|
|
|
- \Log::error('回调验证错误');
|
|
|
|
- $data = [
|
|
|
|
- 'err_no' => 1,
|
|
|
|
- 'err_tips' => 'fail'
|
|
|
|
- ];
|
|
|
|
- } else {
|
|
|
|
- $order = json_decode($notify['msg'], true);
|
|
|
|
- //处理订单
|
|
|
|
- $payId = $order['cp_orderno'];
|
|
|
|
-
|
|
|
|
- $pay = Pay::find($payId);
|
|
|
|
- $pay->pay_type = $order['way'];
|
|
|
|
- $pay->serial_number = $order['channel_no'];
|
|
|
|
- $pay->status = $order['status'] == 'SUCCESS';
|
|
|
|
- $pay->pay_dt = Carbon::now()->toDateString();
|
|
|
|
- $pay->save();
|
|
|
|
|
|
+ return $this->post($this->API::LOGIN, [
|
|
|
|
+ 'appid' => $this->appId,
|
|
|
|
+ 'secret' => $this->secret,
|
|
|
|
+ 'code' => $code,
|
|
|
|
+ ]);
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 接口请求
|
|
|
|
+ *
|
|
|
|
+ * @param string $uri
|
|
|
|
+ * @param array $data
|
|
|
|
+ * @return array|mixed
|
|
|
|
+ * @throws \Exception
|
|
|
|
+ */
|
|
|
|
+ protected function post($uri = '', $data = []) : array
|
|
|
|
+ {
|
|
|
|
+ try {
|
|
|
|
+ $client = new Client();
|
|
|
|
+ $res = $client->post($uri, [
|
|
|
|
+ 'verify' => false,
|
|
|
|
+ 'headers' => ['Content-Type' => 'application/json'],
|
|
|
|
+ 'body' => json_encode($data)
|
|
|
|
+ ]);
|
|
|
|
+ $stringBody = (string)$res->getBody();
|
|
|
|
+ $res = json_decode($stringBody, true);
|
|
|
|
|
|
- $data = [
|
|
|
|
- 'err_no' => 0,
|
|
|
|
- 'err_tips' => 'success'
|
|
|
|
- ];
|
|
|
|
|
|
+ if(!empty($res['err_no'])){
|
|
|
|
+ throw new \Exception("请求字节跳动API接口错误,错误码:{$res['err_no']},错误信息:{$res['err_tips']}");
|
|
|
|
+ }
|
|
|
|
+ return $res['data'];
|
|
|
|
+ } catch (GuzzleException $e) {
|
|
|
|
+ \Log::error($e->getMessage());
|
|
|
|
+ throw new \Exception($e->getMessage());
|
|
}
|
|
}
|
|
- return response()->json($data);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- private function getNoticeData()
|
|
|
|
|
|
+ protected function setAccessFileDir(): void
|
|
{
|
|
{
|
|
- $notify = \request()->all();
|
|
|
|
- $notify = '{"msg":"{\"appid\":\"tt5b312d8cc40f46b701\",\"cp_orderno\":\"10022082800824490007\",\"cp_extra\":\"\",\"way\":\"2\",\"channel_no\":\"2022082822001477591433078541\",\"channel_gateway_no\":\"\",\"payment_order_no\":\"PCP2022082822540531221069106962\",\"out_channel_order_no\":\"2022082822001477591433078541\",\"total_amount\":1,\"status\":\"SUCCESS\",\"seller_uid\":\"71227862181355706950\",\"extra\":\"\",\"item_id\":\"\",\"paid_at\":1661698458,\"message\":\"\",\"order_id\":\"7136939355201063205\",\"trade_item_list\":null,\"ec_pay_trade_no\":\"NEP2022082822540409483061846962\"}","msg_signature":"804a60e48936b14a739230cef21fe6204427732e","nonce":"78","timestamp":"1661698459","type":"payment"}';
|
|
|
|
- //获取订单信息
|
|
|
|
- $notify = json_decode($notify,true);
|
|
|
|
- \Log::info('抖音支付回调==>'.json_encode($notify,JSON_UNESCAPED_SLASHES));
|
|
|
|
-
|
|
|
|
- if($notify['msg_signature'] !== $this->getNotifySign($notify)){
|
|
|
|
- throw new \Exception('签名验证错误');
|
|
|
|
- }
|
|
|
|
|
|
+ $this->accessTokenDir = storage_path('app/bytedance');
|
|
|
|
+ }
|
|
|
|
|
|
- return json_decode($notify['msg'], true);
|
|
|
|
|
|
+ protected function setAccessFilePath(): void
|
|
|
|
+ {
|
|
|
|
+ $this->accessTokenFile = storage_path('app/bytedance/bytedance_access_token.json');
|
|
}
|
|
}
|
|
}
|
|
}
|