= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp); // $verifiedStatus = Rsa::verify( // Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody), // $inWechatpaySignature, // $platformPublicKeyInstance // ); // if ($timeOffsetStatus && $verifiedStatus) { if ($timeOffsetStatus) { $inBodyArray = (array)json_decode($inBody, true); ['resource' => [ 'ciphertext' => $ciphertext, 'nonce' => $nonce, 'associated_data' => $aad ]] = $inBodyArray; $inBodyResource = AesGcm::decrypt($ciphertext, $apiv3Key, $nonce, $aad); return (array)json_decode($inBodyResource, true); } else { return false; } } public function builder($config) { self::$mp_config = $config; $merchantPrivateKeyFilePath = 'file://' . self::$mp_config['pem_path']; $platformCertificateFilePath = 'file://' . self::$mp_config['cer_path']; $merchantId = self::$mp_config['mchid']; $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE); self::$mp_config['pem_key'] = $merchantPrivateKeyInstance; $merchantCertificateSerial = self::$mp_config['cer_num']; $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC); $platformCertificateSerial = self::$mp_config['v3']; self::$mp_instance = Builder::factory([ 'mchid' => $merchantId, 'serial' => $merchantCertificateSerial, 'privateKey' => $merchantPrivateKeyInstance, 'certs' => [ $platformCertificateSerial => $platformPublicKeyInstance, ], ]); } public function refund($config) { $res = false; try { $resp = self::$mp_instance ->v3->refund->domestic->refunds ->post([ 'json' => [ 'transaction_id' => $config['transaction_id'], 'out_refund_no' => $config['out_refund_no'], 'amount' => [ 'refund' => $config['total'], 'total' => $config['total'], 'currency' => 'CNY', ], ], ]); $res = json_decode($resp->getBody(), true); } catch (\Exception $e) { if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) { $r = $e->getResponse(); $res = json_decode($r->getBody(), true); } } return $res; } public function create($config) { $res = false; try { $post_data = [ 'appid' => self::$mp_config['appid'], 'mchid' => self::$mp_config['mchid'], 'description' => $config['description'], 'out_trade_no' => $config['out_trade_no'], 'notify_url' => $config['notify_url'], 'amount' => [ 'total' => $config['total'], ], 'payer' => [ 'openid' => $config['openid'] ] ]; $resp = self::$mp_instance ->v3->pay->transactions->jsapi ->post([ 'json' => $post_data, ]); $res = json_decode($resp->getBody(), true); } catch (\Exception $e) { if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) { $r = $e->getResponse(); $res = json_decode($r->getBody(), true); } } $params = [ 'appId' => self::$mp_config['appid'], 'timeStamp' => (string)time(), 'nonceStr' => self::nonce(), 'package' => 'prepay_id=' . $res['prepay_id'], ]; $params += ['paySign' => Rsa::sign( Formatter::joinedByLineFeed(...array_values($params)), self::$mp_config['pem_key'] ), 'signType' => 'RSA']; $wc_chat_pay_log = new WeChatPayLog(); $wc_chat_pay_log->out_trade_no = $config['out_trade_no']; $wc_chat_pay_log->post_data = json_encode($post_data, JSON_UNESCAPED_UNICODE); $wc_chat_pay_log->params = json_encode($params, JSON_UNESCAPED_UNICODE); $wc_chat_pay_log->save(); return [ 'appid' => $params['appId'], 'timestamp' => $params['timeStamp'], 'nonce_str' => $params['nonceStr'], 'package' => $params['package'], 'pay_sign' => $params['paySign'], 'sign_type' => $params['signType'], ]; } public function check($out_trade_no) { $res = false; try { $resp = self::$mp_instance ->v3->pay->transactions->outTradeNo->_out_trade_no_ ->get([ 'query' => ['mchid' => self::$mp_config['mchid']], 'out_trade_no' => (string)$out_trade_no, ]); $res = json_decode($resp->getBody(), true); } catch (\Exception $e) { if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) { $r = $e->getResponse(); $res = json_decode($r->getBody(), true); } } return $res; } public static function nonce($l = 16) { $charts = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz0123456789"; $max = strlen($charts) - 1; $noncestr = ""; for ($i = 0; $i < $l; $i++) { $noncestr .= $charts[rand(0, $max)]; } return $noncestr; } public function pay($open_id, $app_id, $out_trade_no, $price, $description) { $we_chat_pay = WeChatPay::where('app_id', $app_id)->first(); if (!$we_chat_pay) return false; self::builder([ 'appid' => $we_chat_pay->app_id, 'pem_path' => base_path($we_chat_pay->key), 'cer_path' => base_path($we_chat_pay->crt), 'cer_num' => $we_chat_pay->number, 'mchid' => $we_chat_pay->pay_id, 'v3' => $we_chat_pay->v3, ]); return self::create([ 'description' => $description, 'out_trade_no' => $out_trade_no, 'notify_url' => $we_chat_pay->notify_url, 'total' => $price * 100, 'openid' => $open_id, ]); } public function pay_test(Request $request) { $app_id = $request->post('app_id'); $open_id = $request->post('open_id'); $info = self::pay( $open_id, $app_id, time() . rand(1000, 9999), 0.01, '测试支付' ); return Yo::echo([ 'info' => $info ]); } public function callback_test($app_id) { $input = file_get_contents('php://input'); $headers = request()->header(); $we_chat_pay = WeChatPay::where('app_id', $app_id)->first(); if (!$we_chat_pay) return false; $res = $this->callback($input, $headers, $we_chat_pay->v3, 'file://' . base_path($we_chat_pay->crt)); if (!!$res) { if ($res['trade_state'] == 'SUCCESS') { $we_chat_pay_log = WeChatPayLog::where('out_trade_no', $res['out_trade_no'])->first(); if (!!$we_chat_pay_log) { $we_chat_pay_log->callback = json_encode([ 'type' => 'callback', 'input' => $input, 'headers' => $headers, 'res' => $res, ], JSON_UNESCAPED_UNICODE); $we_chat_pay_log->save(); } } } return Lu::exit([ 'code' => 'SUCCESS', 'message' => '成功', ]); } }