微信开发笔记:微信扫码支付详解

作为一个PC端的在线购物类网站,具备微信支付的功能自然是必须要有的,那么我们就来详细的看一下微信支付平台提供的微信扫码支付的使用流程:

首先你必须要有一个完成认证的服务号,申请开通微信支付功能,我们可以获得appid 和mch_id (也称为partnerid),之后就会是一个向微信支付平台提交一个支付请求来换取一个支付链接的过程:

class wxpay{

    function __construct(){
        $this->wxpay();
    }
    function wxpay(){
    }

    /**
     * 生成支付二维码
     * @param   array   $order      订单信息
     * @param   array   $payment    支付方式信息
     */
    function get_code($order){
        $parameter = array(
        'appid'     =>  APPID,
        'mch_id'    =>  MCHID,
        'nonce_str'    => strtolower(md5(mt_rand())),
        'body'        => "订单支付",
        'out_trade_no'=> $order['order_sn'], // 此处填写订单号
        'product_id'    => $order['order_sn'],   // 此处填写产品号
        'total_fee'    => $order['order_amount']*100,
        'spbill_create_ip'=> $_SERVER["REMOTE_ADDR"],
        'notify_url'    => "http://****.com/respond_wxpay.php",
        'trade_type'    => "NATIVE"
        );
    // 获取code url
    $code_url = $this->getCodeUrl($parameter,PARTNER_KEY);return $code_url;
}

    /**
     * 作用:生成签名
     */
public function getSign($Obj,$key){
    foreach ($Obj as $k => $v) {
        $Parameters[$k] = $v;
    }
    // 签名步骤一:按字典序排序参数
    ksort($Parameters);
        
    $buff = "";
    foreach ($Parameters as $k => $v) {
        $buff .= $k . "=" . $v . "&";
    }
    $String="";
    if (strlen($buff) > 0) {
        $String = substr($buff, 0, strlen($buff) - 1);
    }
    // 签名步骤二:在string后加入KEY
    $String = $String . "&key=" . $key;
    // 签名步骤三:MD5加密
    $String = md5($String);
    // 签名步骤四:所有字符转为大写
    $result_ = strtoupper($String);
    return $result_;
}

/**
 * 获取code url
 */
function getCodeUrl($parameters,$key){
    // 设置接口链接
    $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    try {
        // 检测必填参数
        if ($parameters["out_trade_no"] == null) {
            throw new Exception("缺少统一支付接口必填参数out_trade_no!" . "<br>");
        } elseif ($parameters["body"] == null) {
            throw new Exception("缺少统一支付接口必填参数body!" . "<br>");
        } elseif ($parameters["total_fee"] == null) {
            throw new Exception("缺少统一支付接口必填参数total_fee!" . "<br>");
        } elseif ($parameters["notify_url"] == null) {
            throw new Exception("缺少统一支付接口必填参数notify_url!" . "<br>");
        } elseif ($parameters["trade_type"] == null) {
            throw new Exception("缺少统一支付接口必填参数trade_type!" . "<br>");
        }
            
        $parameters["sign"] = $this->getSign($parameters,$key);
        $xml = "<xml>";
        foreach ($parameters as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
    } catch (Exception $e) {
        die($e->getMessage());
    }

    $response = $this->postXmlCurl($xml, $url, 30);

    $result = json_decode(json_encode(simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
    $code_url = $result["code_url"];

    return $code_url;   
}
    /**
     * 作用:以post方式提交xml到对应的接口url
     */
    public function postXmlCurl($xml, $url, $second = 30)
    {
        // 初始化curl
        $ch = curl_init();
        // 设置超时
        curl_setopt($ch, CURLOP_TIMEOUT, $second);
        // 这里设置代理,如果有的话
        // curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
        // 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, FALSE);
        // 设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        // 要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        // post提交方式
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        // 运行curl
        
        $data = curl_exec($ch);
        curl_close($ch);
        // 返回结果
        if ($data) {
            curl_close($ch);
            return $data;
        } else {
            $error = curl_errno($ch);
            echo "curl出错,错误码:$error" . "<br>";
            echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>错误原因查询</a></br>";
            curl_close($ch);
            return false;
        }
    }    

 于是通过 $wxpay->get_code 的这个方法,将我们的订单转换成了一个可以使用微信扫码支付的一个链接,剩下的就是将这个链接转换成一个二维码了,这个通过phpqrcode等工具还是可以轻松实现的,这里就不多啰嗦了,还是顺便提个醒,在将code_url进行传值的时候建议用urlencode+base64_encode之后进行传输,避免一些特殊字符导致的传输失败。