PHP 如何使用v3支付

问题:
#API证书是通过证书工具下载生成(windows版本 :https://wx.gtimg.com/mch/files/WXCertUtil.exe)%E7%9A%84%E3%80%82%E5%B9%B6%E4%B8%94%E6%94%BE%E5%88%B0%E4%BA%86%E9%A1%B9%E7%9B%AE%E7%9A%84%E6%96%87%E4%BB%B6%E4%B8%8B%EF%BC%8C%E5%9C%A8PHP%E5%8A%A0%E8%BD%BD%E8%AF%81%E4%B9%A6%E6%97%B6curl_exec%E8%BF%94%E5%9B%9E%E7%9A%84%E9%94%99%E8%AF%AF%E4%BF%A1%E6%81%AF%E6%97%B658%EF%BC%8C%E6%A0%B9%E6%8D%AE%E9%94%99%E8%AF%AF%E5%AF%B9%E6%AF%94%EF%BC%8C%E8%AF%B7%E9%97%AE%E5%A6%82%E4%BD%95%E8%A7%A3%E5%86%B3%EF%BC%9F
#代码片段:

/**
     * 微信支付请求接口(POST)
     * @param string $openid     openid
     * @param string $body         商品简单描述
     * @param string $order_sn  订单编号
     * @param string $total_fee 金额
     * @param string $notify_url 回调地址
     * @return  json的数据
     */
    public function wxpay($openid,$total_fee,$body,$order_sn,$notify_url){
        $config = $this->config;
        
        //统一下单参数构造
        $unifiedorder = array(
            'appid'            => $config['appid'],
            'mch_id'        => $config['mch_id'],
            'nonce_str'        => self::getNonceStr(),
            'body'            => $body,
            'out_trade_no'    => $order_sn,
            'total_fee'        => $total_fee * 100,
            'spbill_create_ip'    => self::getip(),
            'notify_url'    => 'http://'.$_SERVER['HTTP_HOST'].'/notify.php',
            'trade_type'    => 'JSAPI',
            'openid'        => $openid
        );
        $unifiedorder['sign'] = self::makeSign($unifiedorder);
        
        //return $unifiedorder;
        
        //请求数据,统一下单
        $xmldata = self::array2xml($unifiedorder);
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $res = self::curl_post_ssl($url, $xmldata);
        Log::record("curl_post_ssl   返回");
        Log::record($res);
        if(!$res){
            return array('status'=>0, 'msg'=>"Can't connect the server" );
        }
        // 这句file_put_contents是用来查看服务器返回的结果 测试完可以删除了
        //file_put_contents('./log.txt',$res,FILE_APPEND);
        
        $content = self::xml2array($res);
        if(strval($content['result_code']) == 'FAIL'){
            return array('status'=>0, 'msg'=>strval($content['err_code']).':'.strval($content['err_code_des']));
        }
        if(strval($content['return_code']) == 'FAIL'){
            return array('status'=>0, 'msg'=>strval($content['return_msg']));
        }
        
        $time = time();
        settype($time, "string");          //jsapi支付界面,时间戳必须为字符串格式
        $resdata = array(
            'appId'          => strval($content['appid']),
            'nonceStr'      => strval($content['nonce_str']),
            'package'       => 'prepay_id='.strval($content['prepay_id']),
            'signType'        => 'MD5',
            'timeStamp'        => $time
        );
        $resdata['paySign'] = self::makeSign($resdata);
        
        return json_encode($resdata);
    }
/**
     * 微信支付发起请求
     */
    protected function curl_post_ssl($url, $xmldata, $second=30,$aHeader=array()){
        $config = $this->config;
        
        $ch = curl_init();
        //超时时间
        curl_setopt($ch,CURLOPT_TIMEOUT,$second);
        curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1);
        //这里设置代理,如果有的话
        //curl_setopt($ch,CURLOPT_PROXY, '10.206.30.98');
        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
        curl_setopt($ch,CURLOPT_URL,$url);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
        curl_setopt($ch, CURLOPT_SSLVERSION, 1);
        
        //默认格式为PEM,可以注释
        curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
        //curl_setopt($ch,CURLOPT_SSLCERT,$config['api_cert']);
        
        curl_setopt($ch,CURLOPT_SSLCERT, ROOT_PATH.'/public/wxcert/'. 'apiclient_cert.pem');
        
        
        //默认格式为PEM,可以注释
        curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
        //curl_setopt($ch,CURLOPT_SSLKEY,$config['api_key']);
        curl_setopt($ch,CURLOPT_SSLKEY,ROOT_PATH.'/public/wxcert/'. 'apiclient_key.pem');
        
        //curl_setopt($ch,CURLOPT_CAINFO,$config['rootca']);
        Log::record("call api_cert, api_cert:".$config['api_cert']);
        if( count($aHeader) >= 1 ){
            curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);
        }
     
        curl_setopt($ch,CURLOPT_POST, true);
        curl_setopt($ch,CURLOPT_POSTFIELDS,$xmldata);
        **$data = curl_exec($ch);**
        if($data){
            curl_close($ch);
            return $data;
        }else { 
            $error = curl_errno($ch);
            echo "call faild, errorCode:$error\n"; 
        **    Log::record("call faild, errorCode:".$error);**//此处返回:58错误代码
            curl_close($ch);
            return false;
        }
    }



#根据错误代码查看:

img

      Not used in modern versions
 CURLE            SSL        CERTPROBLEM                        (58)
     problem with the local client certificate.
           SSL  CURLE                    CLPHER               (59

各位,这个问题如何解决啊

<?php

require_once('vendor/autoload.php');

use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Util\PemUtil;

// 设置参数

// 商户号
$merchantId = '190000****';

// 从本地文件中加载「商户API私钥」,步骤2生成的API私钥文件
$merchantPrivateKeyFilePath = 'file:///path/to/merchant/apiclient_key.pem';
$merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);

// 「商户API证书」的「证书序列号」,步骤2生成的序列号
$merchantCertificateSerial = '3775B6A45ACD588826D15E583A95F5DD********';

//「微信支付平台证书」,步骤3生成的证书
$platformCertificateFilePath = 'file:///path/to/wechatpay/cert.pem';
$platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);

// 从「微信支付平台证书」中获取「证书序列号」,步骤3生成的证书
$platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);

// 构造一个 APIv3 客户端实例
$instance = Builder::factory([
    'mchid'      => $merchantId,
    'serial'     => $merchantCertificateSerial,
    'privateKey' => $merchantPrivateKeyInstance,
    'certs'      => [
        $platformCertificateSerial => $platformPublicKeyInstance,
    ],
]);

// 发送请求
$resp = $instance->chain('v3/certificates')->get(
    ['debug' => true] // 调试模式,https://docs.guzzlephp.org/en/stable/request-options.html#debug
);
echo $resp->getBody(), PHP_EOL;

引用chatGPT作答,这个错误似乎与使用SSLv3或TLSv1协议有关,这些协议在现代PHP版本中被默认禁用,因为它们不再被认为是安全的。错误代码58表示SSL连接无法建立。

为解决此错误,您可以尝试以下步骤:

1.将PHP版本升级到最新的稳定版本。如果您使用的是较旧的PHP版本,则可能不支持较新且更安全的SSL/TLS协议。

2.检查远程服务器是否支持您正在使用的SSL/TLS协议。您可以尝试使用其他协议,如TLSv1.2或TLSv1.3。

3.检查正在使用的SSL证书是否有效且受信任。如果证书已过期或未由受信任的证书颁发机构(CA)颁发,则SSL连接可能失败。

4.在您的PHP配置中启用适当的SSL/TLS协议和密码套件。您可以通过修改php.ini文件中的openssl.cafile和openssl.capath设置来实现此操作。

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
根据代码中的注释,我们可以得知这个问题是在使用curl_exec时发生的。具体来说,根据curl_exec返回的结果是false或者null,这个错误可能与一下几个问题之一有关:

  1. 证书问题

根据代码中的注释,我们可以得知证书的路径是硬编码在代码中的,这可能会导致证书找不到的问题。为了解决这个问题,我们可以尝试更新证书的路径使其与实际路径匹配。

  1. IP/主机名解析问题

由于我们使用了SSL加密,可能会出现IP/主机名解析问题。为了解决这个问题,您可以尝试在请求之前使用以下代码进行解析:

$ip = gethostbyname($hostname);

其中,$hostname是您要请求的主机名或域名。$ip是您获取到的IP地址。

  1. 服务器端口问题

服务器可能无法连接到您指定的端口。在这种情况下,您可以尝试检查您的端口号是否正确,并确保服务器端口没有被防火墙屏蔽。

  1. PHP编译问题

由于PHP的编译问题,可能会导致curl_exec无法正常工作。解决这个问题的方法是重新编译PHP并启用CURL。这个问题比较棘手,如果您不知道如何重新编译PHP,请参考PHP官方文档或咨询您的PHP服务提供商。

希望这些解决方案能够帮到您,如果您需要更详细的帮助,可以提供更多的错误信息或相关代码片段。
如果我的回答解决了您的问题,请采纳!