getPayConfig(); if ($payConfig->typeIsApp()) { $body['appid'] = $payConfig->pay->wx->appId; } else { $body['appid'] = $payConfig->appId; } $body['mchid'] = $payConfig->pay->wx->mchId; $body['description'] = $payConfig->getBody(); $body['out_trade_no'] = $orderNo; $body['notify_url'] = $payConfig->getNotifyUrl(); $body['amount'] = ['total' => $total, 'currency' => $payConfig->getCurrency()]; return $body; } /** * @param string $sign * @param string $json * @return Client */ public function createClient(string $sign, string $json): Client { $client = new Client('api.mch.weixin.qq.com', 80, TRUE); $client->withAddedHeader('Authorization', $sign) ->withContentType('application/json')->withAddedHeader('User-Agent', 'application/json') ->withAddedHeader("Accept", "*/*"); if (!empty($json)) { $client->withBody($json); } $proxyHost = $this->getPayConfig()->getProxyHost(); $proxyPort = $this->getPayConfig()->getProxyPort(); if (!empty($proxyHost) && $proxyPort > 0) { $client->withProxyHost($proxyHost)->withProxyPort($proxyPort); } return $client; } /** * @param string $orderNo * @return array * @throws Exception */ public function searchByOutTradeNo(string $orderNo): array { $config = $this->getPayConfig(); $sign = $this->signature('POST', '/v3/pay/transactions/out-trade-no/' . $orderNo . '?mchid=' . $config->pay->wx->mchId, ""); var_dump($sign); $client = $this->createClient($sign, ""); $client->get('/v3/pay/transactions/out-trade-no/' . $orderNo . '?mchid=' . $config->pay->wx->mchId); $client->close(); $json = json_decode($client->getBody(), TRUE); if (!isset($json['prepay_id'])) { throw new Exception('微信支付调用失败: ' . $client->getBody()); } return $this->createResponse($json, null); } /** * @param string $http_method * @param string $canonical_url * @param string $body * @return string * @throws Exception */ public function signature(string $http_method, string $canonical_url, string $body = ''): string { $payConfig = $this->getPayConfig(); $rand = md5(random_bytes(32)); $time = time(); $message = sprintf("%s\n%s\n%d\n%s\n%s\n", $http_method, $canonical_url, $time, $rand, $body); $sign = $this->openssl_signature($message); return sprintf('%s mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"', $payConfig->pay->wx->schema, $payConfig->pay->wx->mchId, $rand, $time, $payConfig->pay->wx->SerialNumber, $sign); } /** * @param string $body * @return string */ public function openssl_signature(string $body): string { $payConfig = $this->getPayConfig(); $mch_private_key = openssl_get_privatekey(file_get_contents($payConfig->pay->wx->mchKey)); openssl_sign($body, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption'); return base64_encode($raw_sign); } /** * @param array $json * @param array $body * @return array */ private function createResponse(array $json, array $body): array { $responseArray['appId'] = $body['appid']; $responseArray['timeStamp'] = (string)time(); $responseArray['nonceStr'] = Help::random(32); $responseArray['package'] = "prepay_id=" . $json['prepay_id']; $responseBody = $responseArray['appId'] . PHP_EOL . $responseArray['timeStamp'] . PHP_EOL . $responseArray['nonceStr'] . PHP_EOL . $responseArray['package'] . PHP_EOL; $responseArray['signType'] = 'RSA'; $responseArray['signBody'] = $responseBody; $responseArray['paySign'] = $this->openssl_signature($responseBody); $responseArray['prepay_id'] = $json['prepay_id']; return $responseArray; } /** * @param string $ciphertext * @param string $v3Key * @param string $iv * @param string $aad * @return array */ public function decrypt(string $ciphertext, string $v3Key, string $iv = '', string $aad = ''): array { $ciphertext = base64_decode($ciphertext); $authTag = substr($ciphertext, $tailLength = 0 - BLOCK_SIZE); $tagLength = strlen($authTag); /* Manually checking the length of the tag, because the `openssl_decrypt` was mentioned there, it's the caller's responsibility. */ if ($tagLength > BLOCK_SIZE || ($tagLength < 12 && $tagLength !== 8 && $tagLength !== 4)) { throw new \RuntimeException('The inputs `$ciphertext` incomplete, the bytes length must be one of 16, 15, 14, 13, 12, 8 or 4.'); } $plaintext = openssl_decrypt(substr($ciphertext, 0, $tailLength), ALGO_AES_256_GCM, $v3Key, OPENSSL_RAW_DATA, $iv, $authTag, $aad); if (false === $plaintext) { throw new \UnexpectedValueException('Decrypting the input $ciphertext failed, please checking your $key and $iv whether or nor correct.'); } return json_decode($plaintext, true); } }