引言

如果有直接生成二维码的需求,就需要安装下面的依赖

composer require endroid/qr-code

然后导入

use Endroid\QrCode\QrCode;
use Endroid\QrCode\Writer\PngWriter;

使用

支付

    public static function generatePayQrCode($orderId, $desc = '', $price = 0.01, $notifyUrl = '')
    {
        // 获取配置
        extract(self::getConfig());
        //获取32位的随机字符串
        $nonce_str = substr(str_shuffle('abcdefghijklmnopqrstuvwxyz0123456789'), 0, 32);
        //封装参数
        $params = [
            'appid' => $appid,  //应用id
            'mch_id' => $machid,    //商家号
            'nonce_str' => $nonce_str,  //随机数
            'body' => $desc,    //订单描述
            'out_trade_no' => $orderId, //订单号
            'total_fee' => (int)round($price * 100), // 单位:分,如11元就是1100
            'notify_url' => $notifyUrl, //回调地址
            'trade_type' => 'NATIVE', // 扫码支付
        ];

        // 签名
        $params['sign'] = self::makeSign($params);
        // 转 XML
        $xml = self::arrayToXml($params);

        // 请求微信统一下单接口
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $result = self::postXmlCurl($xml, $url);

        //处理返回结果
        $xml = simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NOENT);
        $response = simpleXmlToArray($xml);

        if ($response['return_code'] == 'SUCCESS' && $response['result_code'] == 'SUCCESS') {
            /**
             * 如果不想要base64图片,直接   return $response['code_url'];   就可以了
             */
            $code_url = $response['code_url'];
            // 生成二维码
            $qrCode = new QrCode($code_url);
            //创建写入器
            $writer = new PngWriter();
            //生成二维码
            $result = $writer->write($qrCode);
            // 转为 base64
            $base64Data = base64_encode($result->getString());

            //return $base64Data;
            return $response['code_url'];
        } else {
            throw new Exception("微信下单失败: " . $response['return_msg']);
        }
    }

    // 签名
    private static function makeSign($params)
    {
        ksort($params);
        $string = '';
        foreach ($params as $k => $v) {
            if ($v !== '' && $k != 'sign') {
                $string .= "{$k}={$v}&";
            }
        }
        // APIV3的秘钥
        $aesKey = config('wechat.developer.pay.AesKey');

        $string .= "key={$aesKey}";
        return strtoupper(md5($string));
    }

    // 转 XML
    private static function arrayToXml($data)
    {
        $xml = '<xml>';
        foreach ($data as $key => $value) {
            $xml .= "<{$key}>{$value}</{$key}>";
        }
        $xml .= '</xml>';
        return $xml;
    }

    //处理返回结果
    private static function simpleXmlToArray($xml)
    {
        if ($xml === null) return null;

        $array = (array)$xml;

        foreach ($array as $key => $value) {
            if (is_object($value) || is_array($value)) {
                $array[$key] = simpleXmlToArray($value);
            }
        }

        return $array;
    }

    //发起请求
    private static function postXmlCurl($xml, $url, $timeout = 30)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    }

回调

     //获取数据及解析数据
     $xml = file_get_contents('php://input') ?: '';
     $data = $this->xmlToArray($xml);

    //解析$xml数据
    private function xmlToArray($xml)
    {
        $previous = libxml_use_internal_errors(true);
        libxml_clear_errors();

        $xml = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOENT | LIBXML_NOCDATA);
        $json = json_encode($xml, JSON_UNESCAPED_UNICODE);
        $array = json_decode($json, true);

        // 清理错误
        libxml_clear_errors();
        libxml_use_internal_errors($previous);

        return $array;
    }

回调地址不要使用小程序支付(JSAPI)的回调接口,因为Native的回调数据是 XML 格式,通过原始请求体(raw body)发送,而不是 application/x-www-form-urlencoded表单格式,所以$_POST和 input('post.')压根拿不到数据

最后修改:2025 年 09 月 18 日
如果觉得我的文章对你有用,请随意赞赏