zoukankan      html  css  js  c++  java
  • 微信扫码支付精简版

    其实这个文档仅仅作为参考,如果应用到线上请完成签名验证

    1.因为微信支付sdk非常全全面,而我值需要扫码支付即可,所以就把主要的代码提出来了

    <?php
    
    class WxApi {
        private $config = array();
        private $unifiedorder_url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        private $sign = NULL ;
        
        public function __construct($config = array()){
            $this -> config = $config ;
            
        }
        
        /**
         * @desc 统一下单接口
         * 
         * 
         */
        public function unifiedOrder($input = array()){
            $return = array();
            //检查必填参数
            if(!$input['out_trade_no']){
                $return['code_status'] = 1 ;
                $return['code_messate'] = '缺少统一支付接口必填参数out_trade_no!' ;
            }else if(!$input['body']){
                $return['code_status'] = 2 ;
                $return['code_messate'] = '缺少统一支付接口必填参数body!' ;
            }else if(!$input['total_fee']){
                $return['code_status'] = 3 ;
                $return['code_messate'] = '缺少统一支付接口必填参数total_fee!' ;
            }else if(!$input['trade_type']){
                $return['code_status'] = 4 ;
                $return['code_messate'] = '缺少统一支付接口必填参数trade_type!' ;
            }
            
            
            if($input['trade_type'] == 'JSAPI' && !$input['openid']){
                $return['code_status'] = 5 ;
                $return['code_messate'] = '统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!' ;
            }
            
            if($input['trade_type'] == 'NATIVE' && !$input['product_id']){
                $return['code_status'] = 5 ;
                $return['code_messate'] = 'trade_type=NATIVE时,此参数必传。此参数为二维码中包含的商品ID,商户自行定义。' ;
            }
            
            if(!$input['notify_url'] && $this -> config['notify_url'] != '' ){
                $input['notify_url'] = $this -> config['notify_url'];
            }
            
            //当缺少必要参数时需要返回数据重新配置必须的参数
            if(!empty($return)){
                return $return ;
            }
            
            $input['appid'] = $this -> config['appid'];
            $input['mch_id'] = $this -> config['mch_id'];
            $input['spbill_create_ip'] = $this -> config['ip'];
            $input['nonce_str'] = $this -> getNonceStr();
            
            
            //签名
            $sign = $this -> setMySign($input);
            //var_dump($sign);die;
            $input['sign'] = $sign ;
            $xml = $this -> arrayToXml($input);
            
            //开始请求订单
            $response = $this -> postXmlCurl($this -> config,$xml,$this -> unifiedorder_url,false,6);
            $result = $this -> xmlToArray($response);
            //这里需要验证一下签名,暂时先不验证 方便测试
            //self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间
            return $result;
            
        }
        
        
        private function setMySign($params,$signType = TRUE){
           
            //签名步骤一:按字典序排序参数并拼接字符串
            ksort($params);
            //var_dump($params);
            $string = "";
            foreach ($params as $k => $v){
                if($k != "sign" && $v != "" && !is_array($v)){
                    $string .= $k . "=" . $v . "&";
                }
            }
            
            $string = trim($string, "&");
            //echo $string ;
            //签名步骤二:在string后加入KEY
            $string = $string . "&key=" . $this -> config['key'];
            //签名步骤三:MD5加密或者HMAC-SHA256
            if($this -> config['sign_type'] == "MD5"){
                $string = md5($string);
            } else if($this -> config['sign_type']  == "HMAC-SHA256") {
                $string = hash_hmac("sha256",$string ,$this -> config['key']);
            }
            //签名步骤四:所有字符转为大写
            $result = strtoupper($string);
            $this -> sign = $result ;
            return $result;
        }
        
        
        /**
         *
         * 产生随机字符串,不长于32位
         * @param int $length
         * @return 产生的随机字符串
         */
        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;
        }
        
        
        /**
         * 输出xml字符
         * @throws WxPayException
         **/
        private function arrayToXml($array = array())
        {
            if(!is_array($array) || count($array) <= 0)
            {
                throw new WxPayException("数组数据异常!");
            }
             
            $xml = "<xml>";
            foreach ($array as $key=>$val)
            {
                if (is_numeric($val)){
                    $xml.="<".$key.">".$val."</".$key.">";
                }else{
                    $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
                }
            }
            $xml.="</xml>";
            return $xml;
        }
        
        /**
         * 将xml转为array
         * @param string $xml
         * @throws WxPayException
         */
        private function xmlToArray($xml)
        {
            if(!$xml){
                throw new WxPayException("xml数据异常!");
            }
            //将XML转为array
            //禁止引用外部xml实体
            libxml_disable_entity_loader(true);
            $array = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
            return $array;
        }
        
        /**
         * 以post方式提交xml到对应的接口url
         *
         * @param WxPayConfigInterface $config  配置对象
         * @param string $xml  需要post的xml数据
         * @param string $url  url
         * @param bool $useCert 是否需要证书,默认不需要
         * @param int $second   url执行超时时间,默认30s
         * @throws WxPayException
         */
        private static function postXmlCurl($config, $xml, $url, $useCert = false, $second = 30)
        {
    
            $ch = curl_init();
            $curlVersion = curl_version();
            $ua = "WXPaySDK/3.0.9 (".PHP_OS.") PHP/".PHP_VERSION." CURL/".$curlVersion['version']." " . $config['mch_id'];   
            //设置超时
            curl_setopt($ch, CURLOPT_TIMEOUT, $second);
            $proxyHost = "0.0.0.0";
            $proxyPort = 0;
            //$config->GetProxy($proxyHost, $proxyPort);
            //如果有配置代理这里就设置代理
            if($proxyHost != "0.0.0.0" && $proxyPort != 0){
                curl_setopt($ch,CURLOPT_PROXY, $proxyHost);
                curl_setopt($ch,CURLOPT_PROXYPORT, $proxyPort);
            }
            curl_setopt($ch,CURLOPT_URL, $url);
            if(stripos($url,"https://")!==FALSE){
                curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
            }else{
                curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
                curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验
            }
            curl_setopt($ch,CURLOPT_USERAGENT, $ua);
            //设置header
            curl_setopt($ch, CURLOPT_HEADER, FALSE);
            //要求结果为字符串且输出到屏幕上
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        
            if($useCert == true){
                //设置证书
                //使用证书:cert 与 key 分别属于两个.pem文件
                //证书文件请放入服务器的非web目录下
                $sslCertPath = $config['sslcert_path'];
                $sslKeyPath = $config['sslkey_path'];
                $config->GetSSLCertPath($sslCertPath, $sslKeyPath);
                curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
                curl_setopt($ch,CURLOPT_SSLCERT, $sslCertPath);
                curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
                curl_setopt($ch,CURLOPT_SSLKEY, $sslKeyPath);
            }
            //post提交方式
            curl_setopt($ch, CURLOPT_POST, TRUE);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
            //运行curl
            $data = curl_exec($ch);
            //返回结果
            if($data){
                curl_close($ch);
                return $data;
            } else {
                $error = curl_errno($ch);
                curl_close($ch);
                die("curl出错,错误码:$error");
            }
        }
        
        
        
    }

    2.使用方法:

    require EXTEND_PATH . 'sdk.php';
    class pay{
        $payConfig = array(
            'appid' => 'wx5f9d09f208cfa',
            'mch_id' => '124002',
            'key' => '8b15d56f894fab8035ac241cb39',
            'app_secret' => '2e3fd5b24241646917265ee',
            'sslcert_path' => '',
            'sslkey_path' => '',
            'ip' => '',
            'sign_type' => 'MD5',
        );
        /**
         * @desc 初始化方法
         */
        public function __construct(){
            
            $this -> weixinConfig['sslcert_path'] = EXTEND_PATH . '/weixinpaysdk-3.0.9/cert/apiclient_cert.pem';
            $this -> weixinConfig['sslkey_path'] = EXTEND_PATH . '/weixinpaysdk-3.0.9/cert/apiclient_key.pem';
            $request = Request::instance();
            $this -> weixinConfig['ip'] = $request -> ip(0,true);
        }  
    
        /**
         * @desc 微信订单
         * @author 646943067@qq.com
         * @version 1.0
         * @date 2018-12-14
         */
        public function getWeixinOrder(){
            
            $wxpayObj = new WxApi($this -> weixinConfig);
            $time = time();
            $input = array(
                'body' => '测试内容',
                'attach' => '鸭题鸭课程PC版本',
                'out_trade_no' => '1234567891',
                'total_fee' => '1',
                'time_start' => date("YmdHis",$time),
                'time_expire' => date("YmdHis", $time + 600),
                'notify_url' => 'http://paysdk.weixin.qq.com/notify.php',
                'trade_type' => 'NATIVE',
                'product_id' => '1000000003',
            );
            
            $result = $wxpayObj -> unifiedOrder($input);
            $QRcode = new QRcode();
            $level = 'L';
            $size =4;
            ob_start();
            $QRcode->png($result['code_url'],false,$level,$size,2);
            $imageString ="data:image/jpg;base64," . base64_encode(ob_get_contents());
            ob_end_clean();
            echo "<img src='$imageString' />";
        }
    
    }
    
    
    $obj = new pay();
    $obj -> getWeixinOrder();
  • 相关阅读:
    Android4.0 以后不允许在主线程进行网络连接
    关于升级linux下apache
    事物复制中大项目(Large Article)出问题如何快速修复
    国企银行面试总结
    Git命令详解(一)-个人使用
    函数体的规模要小,尽量控制在 50 行代码之内
    函数的功能要单一,不要设计多用途的函数
    在函数体的“出口处”,对 return 语句的正确性和效率进行检查
    在函数体的“入口处”,对参数的有效性进行检查
    有些场合用“引用传递”替换“值传 递”可以提高效率
  • 原文地址:https://www.cnblogs.com/ailingfei/p/10118690.html
Copyright © 2011-2022 走看看