已解决
JSAPI产品支付 使用wechatpay-guzzle-middleware SDK 报错 ?微信JSAPI产品支付 使用wechatpay-guzzle-middleware SDK 开发 SAPI调起支付 提示支付验证签名失败1 统一下单的时候 使用的 构造一个实列 $client = new \GuzzleHttp\Client(['handler' => $stack]); 获取 prepay_id 这一步没有问题 2JSAPI调起支付 提示支付验证签名失败 检查可能造成的原因:1 微信文档上说 签名方式: 需与统一下单的签名类型一致 ( 签名类型,默认为MD5,支持HMAC-SHA256和MD5。注意此处需与统一下单的签名类型一致 ) 2 参数的大小写 2 JSAPI调起支付 的签名 与 统一下单的签名不一致 3 JSAPI调起支付生成签名的参数 随机字符串 与 统一下单的随机字符串不一致 问题一:wechatpay-guzzle-middleware SDK 开发是自动验签的 怎么获取 统一下单的 随机字符串 /** * JSAPI支付下单 * 同步请求 * @param $out_trade_no * @param $description * @param $total */ public function JsapiSyncWeChatPay($total,$description,$notify_url,$out_trade_no,$openid,$attach ='') { $data = []; try { if(!$total || !$description || !$notify_url || !$out_trade_no || !$openid){ $data['statusCode'] = 400; $data['msg'] = '缺少必要参数,稍后再试'; return $data; } $time_expire = date("Y-m-d\TH:i:s\Z",strtotime("30*60 seconds") ); $order = [ "time_expire" => $time_expire, //交易结束时间--订单失效时间 "mchid" => WeChatTwo::$merchantId, //直连商户号 Required "appid" => WeChatTwo::$appid, //应用ID Required "notify_url" => $notify_url, //通知地址 Required "out_trade_no"=> $out_trade_no, //商户订单号 Required "amount" => ["total" => $total,"currency" => "CNY"], //订单金额信息 Required "description" => $description, //商品描述 Required "payer" => [ "openid" => $openid, //获取微信用户的$openid ], //"attach" => "自定义数据说明", //附加数据 ]; $url ="https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"; $resp = WeChatTwo::$client->request( 'POST', $url, //请求URL [ // JSON请求体 'json' => $order, 'headers' => [ 'Accept' => 'application/json' ] ] ); $statusCode = $resp->getStatusCode(); if ($statusCode == 200) { //处理成功 $getContents = json_decode($resp->getBody()->getContents()); $data['msg'] = '处理成功'; $data['statusCode'] = 200; $timestamp = time(); $nonce = WeChatTwo::getNonceStr(); $data['appId'] = WeChatTwo::$appid; //公众号ID,由商户传入 $data['timeStamp'] = $timestamp; //时间戳 $data['nonceStr'] = $nonce; //随机串 $data['package'] = "prepay_id=" . $getContents->prepay_id; $data['signType'] = "RSA"; //微信签名方式: $data['paySign'] = WeChatTwo::paySign($url, "POST", "",$timestamp,$nonce); //微信签名 } else if ($statusCode == 204) { //处理成功,无返回Body $data['msg'] = '微信支付统一下单失败';//'处理成功,无返回Body,请刷新后再试'; $data['statusCode'] = 204; } return $data; } catch (RequestException $e) { $data['msg'] = $e->getMessage(); $data['statusCode'] = 400; return $data; /*// 进行错误处理 echo $e->getMessage()."\n"; if ($e->hasResponse()) { echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n"; }*/ } } /** * 生成签名 * @param $appId * @param $timeStamp * @param $nonceStr * @param $package * @return string */ public static function paySign($url = "", $http_method = "POST", $body = "",$timestamp = "",$nonce="") { if (!in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) { throw new RuntimeException("当前PHP环境不支持SHA256withRSA"); } $url_parts = parse_url($url); $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : "")); //当前时间戳 $timestamp = empty($timestamp) ? time() : $timestamp; //随机字符串 $nonce = empty($nonce) ? WeChatTwo::getNonceStr() : $nonce; //POST请求时 需要 转JSON字符串 $message = $http_method."\n". $canonical_url."\n". $timestamp."\n". $nonce."\n". $body."\n"; //生成签名 openssl_sign($message, $raw_sign, openssl_get_privatekey(file_get_contents( WeChatTwo::$merchantPrivateKeyFilePath )), 'sha256WithRSAEncryption'); $sign = base64_encode($raw_sign); return $sign; }
2021-12-31已解决
微信支付v3 jsapi调起支付时,支付验证签名失败?/**html**/ /** *JSAPI支付 **/ function onBridgeReady(result) { alert( result.appId ); alert( result.timeStamp ); alert( result.nonceStr ); alert( result.package ); alert( result.signType ); alert( result.paySign ); WeixinJSBridge.invoke('getBrandWCPayRequest', { "appId" : result.appId, //公众号ID,由商户传入 "timeStamp": result.timeStamp, //时间戳,自1970年以来的秒数 "nonceStr" : result.nonceStr, //随机串 "package" : result.package, "signType" : result.signType, //微信签名方式: "paySign" : result.paySign, //微信签名 }, function (res) { alert( JSON.parse(res) ); if (res.err_msg == "get_brand_wcpay_request:ok") { // 使用以上方式判断前端返回,微信团队郑重提示: //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。 } }); } //****? <?php /** * WeChat pay * 库和SDK wechatpay-guzzle-middleware * User:wang jian * Date:2021.12.24 */ namespace App\Library; use GuzzleHttp\Exception\RequestException; use WechatPay\GuzzleMiddleware\WechatPayMiddleware; use WechatPay\GuzzleMiddleware\Util\PemUtil; use GuzzleHttp\HandlerStack; class WeChatTwo { private static $merchantId; //微信_商户号 private static $appid; //微信开放平台_appid private static $appkey; //微信开放平台_appkey private static $merchantCertificateSerial; //微信_商户API证书序列号 private static $apiv3key; //微信_APIV3密钥 private static $merchantPrivateKeyFilePath; //微信_商户API证书私钥 private static $platformCertificateFilePath; //微信_支付平台证书_初始生成——其它加载 private static $upload_img_api; //图片上传接APIurl private static $client; public function __construct() { WeChatTwo::$merchantId = config('wechat.merchantId'); //微信_商户号 WeChatTwo::$appid = config('wechat.appid'); //微信开放平台_appid WeChatTwo::$appkey = config('wechat.appkey'); //微信开放平台_appkey WeChatTwo::$apiv3key = config('wechat.apiv3key'); //微信开放平台_appkey WeChatTwo::$merchantCertificateSerial = config('wechat.merchantCertificateSerial'); //微信_商户API证书序列号 WeChatTwo::$merchantPrivateKeyFilePath = storage_path('cert'.DIRECTORY_SEPARATOR.'wechat'.DIRECTORY_SEPARATOR.'4C1BBE189365B735FF1B7AE9A63EDCB7CDA49093'.DIRECTORY_SEPARATOR.'apiclient_key.pem');//商户API证书私钥 WeChatTwo::$platformCertificateFilePath = storage_path('cert'.DIRECTORY_SEPARATOR.'wechat'.DIRECTORY_SEPARATOR.'4C1BBE189365B735FF1B7AE9A63EDCB7CDA49093'.DIRECTORY_SEPARATOR.'wechatpay_67BD0BB346B4ABD494092F0F7FCF507A42E48A1E.pem');//微信_支付平台证书_初始生成——其它加载 WeChatTwo::$upload_img_api = 'https://api.mch.weixin.qq.com/v3/merchant/media/upload'; //图片上传接API url WeChatTwo::$client = WeChatTwo::instanceWeChatPay(); } /** * 构建一个客户端实例 * wechatpay-guzzle-middleware,适用于PHP开发者 */ public static function instanceWeChatPay(){ // 商户相关配置, $merchantId = WeChatTwo::$merchantId; // 商户号 $merchantSerialNumber = WeChatTwo::$merchantCertificateSerial; // 商户API证书序列号 $merchantPrivateKey = PemUtil::loadPrivateKey(WeChatTwo::$merchantPrivateKeyFilePath); // 商户私钥文件路径 // 微信支付平台配置 $wechatpayCertificate = PemUtil::loadCertificate(WeChatTwo::$platformCertificateFilePath); // 微信支付平台证书文件路径 // 构造一个WechatPayMiddleware $wechatpayMiddleware = WechatPayMiddleware::builder() ->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey) // 传入商户相关配置 ->withWechatPay([ $wechatpayCertificate ]) // 可传入多个微信支付平台证书,参数类型为array ->build(); // 将WechatPayMiddleware添加到Guzzle的HandlerStack中 $stack =\GuzzleHttp\HandlerStack::create(); $stack->push($wechatpayMiddleware, 'wechatpay'); // 创建Guzzle HTTP Client时,将HandlerStack传入,接下来,正常使用Guzzle发起API请求,WechatPayMiddleware会自动地处理签名和验签 //WeChatTwo::$client = new \GuzzleHttp\Client(['handler' => $stack]); return new \GuzzleHttp\Client(['handler' => $stack]); } /** * JSAPI支付下单 * 同步请求 * @param $out_trade_no * @param $description * @param $total */ public function JsapiSyncWeChatPay($total,$description,$notify_url,$out_trade_no,$openid,$attach ='') { $data = []; try { if(!$total || !$description || !$notify_url || !$out_trade_no || !$openid){ $data['statusCode'] = 400; $data['msg'] = '缺少必要参数,稍后再试'; return $data; } $time_expire = date("Y-m-d\TH:i:s\Z",strtotime("30*60 seconds") ); $order = [ "time_expire" => $time_expire, //交易结束时间--订单失效时间 "mchid" => WeChatTwo::$merchantId, //直连商户号 Required "appid" => WeChatTwo::$appid, //应用ID Required "notify_url" => $notify_url, //通知地址 Required "out_trade_no"=> $out_trade_no, //商户订单号 Required "amount" => ["total" => $total,"currency" => "CNY"], //订单金额信息 Required "description" => $description, //商品描述 Required "payer" => [ "openid" => $openid, //获取微信用户的$openid ], //"attach" => "自定义数据说明", //附加数据 ]; $timestamp = time(); $nonce = WeChatTwo::getNonceStr(); $url ="https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"; $resp = WeChatTwo::$client->request( 'POST', $url, //请求URL [ // JSON请求体 'json' => $order, 'headers' => [ 'Accept' => 'application/json', 'Authorization' => 'WECHATPAY2-SHA256-RSA2048'.WeChatTwo::SignatureGenerate ($url, "POST", "",$timestamp,$nonce), ] ] ); $statusCode = $resp->getStatusCode(); if ($statusCode == 200) { //处理成功 $getContents = json_decode($resp->getBody()->getContents()); $body['appId'] = WeChatTwo::$appid; //公众号ID,由商户传入 $body['timeStamp'] = $timestamp; //时间戳 $body['nonceStr'] = $nonce; //随机串 $body['package'] = "prepay_id=" . $getContents->prepay_id; $body['signType'] = "RSA"; //微信签名方式: $body['paySign'] = WeChatTwo::paySign($url, "POST", $body['package'],$timestamp,$nonce); //微信签名 $data['msg'] = '处理成功'; $data['statusCode'] = 200; $data['body'] = $body; } else if ($statusCode == 204) { //处理成功,无返回Body $data['msg'] = '微信支付统一下单失败';//'处理成功,无返回Body,请刷新后再试'; $data['statusCode'] = 204; } return $data; } catch (RequestException $e) { $data['msg'] = $e->getMessage(); $data['statusCode'] = 400; return $data; /*// 进行错误处理 echo $e->getMessage()."\n"; if ($e->hasResponse()) { echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n"; }*/ } } /** * 生成签名 * @param $appId * @param $timeStamp * @param $nonceStr * @param $package * @return string */ public static function paySign($url = "", $http_method = "POST", $body = "", $timestamp = "", $nonce="") { if (!in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) { throw new RuntimeException("当前PHP环境不支持SHA256withRSA"); } $url_parts = parse_url($url); $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : "")); //当前时间戳 $timestamp = empty($timestamp) ? time() : $timestamp; //随机字符串 $nonce = empty($nonce) ? WeChatTwo::getNonceStr() : $nonce; //POST请求时 需要 转JSON字符串 $message = $http_method."\n". $canonical_url."\n". $timestamp."\n". $nonce."\n". $body."\n"; //生成签名 openssl_sign($message, $raw_sign, openssl_get_privatekey(file_get_contents( WeChatTwo::$merchantPrivateKeyFilePath )), 'sha256WithRSAEncryption'); $sign = base64_encode($raw_sign); return $sign; } /** * 生成 Authorization * @param string $url * @param string $http_method * @param string $body * @return string */ public static function SignatureGenerate ($url = "", $http_method = "POST", $body = "", $timestamp = "", $nonce="") { //当前时间戳 $timestamp = empty($timestamp) ? time() : $timestamp; //随机字符串 $nonce = empty($nonce) ? WeChatTwo::getNonceStr() : $nonce; $sign = WeChatTwo::paySign($url, $http_method, $body,$timestamp,$nonce); //$schema = 'WECHATPAY2-SHA256-RSA2048'; ////Authorization 类型 $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',WeChatTwo::$merchantId, $nonce, $timestamp, WeChatTwo::$merchantCertificateSerial, $sign); return $token; } // 解密数据 public function decryptSign($ciphertext, $associatedData, $nonceStr) { $ciphertext = base64_decode($ciphertext); if (function_exists('\sodium_crypto_aead_aes256gcm_is_available') && \sodium_crypto_aead_aes256gcm_is_available()) { //$APIv3_KEY就是在商户平台后端设置是APIv3秘钥 $orderData = \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, WeChatTwo::$apiv3key); $orderData = json_decode($orderData, true); return $orderData; }else{ //exit('缺乏PHP扩展:sodium,请安装该扩展或切换到PHP7.3+版本'); } return false; } /**将字符串安全编码 * * @param $string * * @return string */ public function urlsafe_b64encode($string) { $data = base64_encode($string); $data = str_replace(array('+', '/', '='), array('-', '_', ''), $data); return $data; } /**将字符串安全解码 * * @param $string * * @return string */ public function urlsafe_b64decode($string) { $data = str_replace(array('-', '_'), array('+', '/'), $string); $mod4 = strlen($data) % 4; if ($mod4) { $data .= substr('====', $mod4); } return base64_decode($data); } /* * 产生随机字符串,不长于32位 * @param int $length * @return string */ public static function getNonceStr($length = 32) { $chars = "abcdefghijklmnopqrstuvwxyz0123456789"; $str = ""; for ($i = 0; $i < $length; $i++) { $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1); } return $str; } }
2021-12-31谢谢,大佬
wechatpay-php 报错Cannot load privateKey fromwechatpay-php 报错 Rsa::from 报错 Cannot load privateKey from(string), please take care about the \$thing input /** * 构建一个客户端实例 * wechatpay-php */ public static function instanceWeChatPay() { // 商户号 $merchantId = WeChat::$merchantId; // 从本地文件中加载商户API私钥,商户API私钥会用来生成请求的签名 //dd(WeChat::$merchantPrivateKeyFilePath); 路径 //"D:\web\3boat\storage\cert\wechat\4C1BBE189365B735FF1B7AE9A63EDCB7CDA49093\apiclient_key.pem" $merchantPrivateKeyInstance = Rsa::from(WeChat::$merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE); dd($merchantPrivateKeyInstance); // 商户API证书序列号 $merchantCertificateSerial = WeChat::$merchantCertificateSerial; // 从本地文件中加载微信支付平台证书,用来验证微信支付应答的签名 $platformPublicKeyInstance = Rsa::from(WeChat::$platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC); // 获取微信支付平台证书序列号 $platformCertificateSerial = PemUtil::parseCertificateSerialNo(WeChat::$platformCertificateFilePath); // 构造一个 APIv3 客户端实例 WeChat::$instance = Builder::factory([ 'mchid' => $merchantId, 'serial' => $merchantCertificateSerial, 'privateKey' => $merchantPrivateKeyInstance, 'certs' => [ $platformCertificateSerial => $platformPublicKeyInstance, ], ]); }
2021-12-30