精华内容
下载资源
问答
  • 微信jsapi支付(微信支付

    千次阅读 2019-05-09 15:35:45
    这里要注意的是h5支付不需要openid,而微信jsapi支付需要openid。jsapi对客户端ip没有要求,而微信h5支付对客户端ip有要求 然后拿到: $appid = ""; //应用 APPID $mch_id = ""; //微信支付商户号 $key = ""; //微信...

    微信h5支付首先商户平台要开通jsapi支付,商户平台要关联公众号,

    这里要注意的是h5支付不需要openid,而微信jsapi支付需要openid。jsapi对客户端ip没有要求,而微信h5支付对客户端ip有要求
    然后拿到:
    $appid = ""; //应用 
    APPID $mch_id = ""; //微信支付商户号 
    $key = ""; //微信商户 API 密钥
    注意配置相关域名和授权目录
    商户平台

    公众平台

    public function pay()
        {
            // 获取openid
            $pr = req::$forms;
            ///查询到的价格
            $sql="select price,id,no from `sm_order` where no='".$pr['oid']."'";
            //echo $sql;die;
            $order = db::queryone($sql);
            //echo '<pre>';print_r($order);die;
            $appAttr = [];
            $appAttr['appid'] = $this->appid;
            $key = $this->key;
            $appAttr['attach'] = '命理学院';
            $appAttr['body'] = '星座运势';
            $appAttr['detail'] = '{"info":"微信支付"}';
            $appAttr['mch_id'] = $this->mch_id;
            $appAttr['nonce_str'] = md5(time().rand(1000,9999));
            $appAttr['notify_url'] = 'https://你的域名/v1.0.0/XcxPay/FaceAiPay/notify.php';
            $appAttr['openid'] = $pr['open_id'];//$_POST['openid'];
            $appAttr['out_trade_no'] = $order['no'];//平台内部订单号
            $appAttr['spbill_create_ip'] = '127.0.0.1';
            $appAttr['total_fee'] = $order['price'] * 100;//单位分
            $appAttr['trade_type'] = 'JSAPI';
    //推荐上面有数据按官方的“ASCII字典”排序的设键放置数据
    
            $appAttr['sign'] = self::getParam($appAttr,false,$key);
            $post_data = "<xml>
                        <appid>".$appAttr['appid']."</appid>
                        <attach>".$appAttr['attach']."</attach>
                        <body>".$appAttr['body']."</body>
                        <mch_id>".$appAttr['mch_id']."</mch_id>
                        <detail>".$appAttr['detail']."</detail>
                        <notify_url>".$appAttr['notify_url']."</notify_url>
                        <nonce_str>".$appAttr['nonce_str']."</nonce_str>
                        <openid>".$appAttr['openid']."</openid>
                        <out_trade_no>".$appAttr['out_trade_no']."</out_trade_no>
                        <spbill_create_ip>".$appAttr['spbill_create_ip']."</spbill_create_ip>
                        <total_fee>".$appAttr['total_fee']."</total_fee>
                        <trade_type>".$appAttr['trade_type']."</trade_type>
                        <sign>".$appAttr['sign']."</sign>
                </xml>";//拼接成 XML 格式
            //echo $post_data;die;
            $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信传参地址
            $dataxml = self::__postXmlCurl($post_data,$url); //后台 POST 微信传参地址  同时取得微信返回的参数
            $objectxml = (array)simplexml_load_string($dataxml, 'SimpleXMLElement', LIBXML_NOCDATA); //将微信返回的 XML 转换成数组
            //echo '<pre>';print_r($objectxml);die;
            $resultData=[];
            $resultData['appId']=$appAttr['appid'];
            $resultData['nonceStr']=$objectxml['nonce_str'];
            $resultData['package']='prepay_id='.$objectxml['prepay_id'];
            $resultData['signType']='MD5';
            $resultData['timeStamp']=(string)time();
            $resultData['paySign']=self::getParam($resultData,false,$key);
            echo json_encode($resultData);
            die;
        }
        public function scanquery(){
            $pr = req::$forms;
            //查询订单状态
            $sql="select status from `sm_order` where no='".$pr['oid']."' and product_id='".$pr['star_id']."'";
            //echo $sql;die;
            $order = db::queryone($sql);
            //echo json_decode($order);die;
            //echo '<pre>';print_r($order);die;
            if($order && $order['status'] == 'PAYED'){
                $url = '/xingzuo/?ct=index&ac=xingzuo_info&oid='.$pr['oid'].'&star_id='.$pr['star_id'];
                echo '{"status":1,"orderId":"'.$pr['oid'].'","url":"'.$url.'"}';
            }else{
                echo '{"code":1,"orderId":"'.$pr['oid'].'"}';
            }
        }
    
        private function __createNoncestr( $length = 32 ){
            $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
            $str ="";
            for ( $i = 0; $i < $length; $i++ )  {
                $str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);
            }
            return $str;
        }
        private function __postXmlCurl($xml,$url,$second = 30){
            $ch = curl_init();
            //设置超时
            curl_setopt($ch, CURLOPT_TIMEOUT, $second);
            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);
            //返回结果
            if($data){
                curl_close($ch);
                return $data;
            }else{
                $error = curl_errno($ch);
                curl_close($ch);
                echo "curl 出错,错误码:$error"."<br>";
            }
        }
        private function __get_client_ip() {
            if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
                $ip = getenv('HTTP_CLIENT_IP');
            } elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
                $ip = getenv('HTTP_X_FORWARDED_FOR');
            } elseif(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
                $ip = getenv('REMOTE_ADDR');
            } elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
                $ip = $_SERVER['REMOTE_ADDR'];
            }
            return preg_match ( '/[\d\.]{7,15}/', $ip, $matches ) ? $matches [0] : '';
        }
        //对参数排序,生成MD5加密签名
    
        private function getParam($paramArray, $isencode=false,$k)
        {
            $paramStr = '';
            ksort($paramArray);
            $i = 0;
            foreach ($paramArray as $key => $value)
            {
                if ($key == 'Signature'){
                    continue;
                }
                if ($i == 0){
                    $paramStr .= '';
                }else{
                    $paramStr .= '&';
                }
                $paramStr .= $key . '=' . ($isencode?urlencode($value):$value);
                ++$i;
            }
            $stringSignTemp=$paramStr."&key=".$k;
            $sign=strtoupper(md5($stringSignTemp));
            return $sign;
        }
    展开全文
  • 微信jsapi支付

    2019-12-26 10:08:15
    微信jsapi 支付可以直接使用 适合微信浏览器使用 //微信jsapi支付 前端 //微信jsapi 支付 后端 public function actionDakaDoneBywx() { // if(input(‘type’) == ) $order[‘user_id’] = $_SESSION[‘user_id’...

    微信jsapi 支付可以直接使用 适合微信浏览器使用

    //微信jsapi支付 前端
    function paySign(){
    if (typeof WeixinJSBridge == “undefined”){
    $.post(’/mobile/index.php?m=user&a=DakaDoneBywx’,{},res=>{
    console.log(res)
    if(res.error_code == 10000){
    // onBridgeReady(res.info);
    }else{
    alert(res.msg)
    }
    },‘json’)
    }else{
    $.post(’/mobile/index.php?m=user&a=DakaDoneBywx’,{},res=>{
    if(res.error_code == 10000){
    onBridgeReady(res.info);
    }else{
    alert(res.msg)
    }
    },‘json’)

    }

    }
    function onBridgeReady(info){
    WeixinJSBridge.invoke(
    ‘getBrandWCPayRequest’,{
    “appId”:info.appId, //公众号名称,由商户传入
    “timeStamp”:info.timeStamp, //时间戳,自1970年以来的秒数
    “nonceStr”:info.nonceStr, //随机串
    “package”:info.package,
    “signType”:“MD5”, //微信签名方式:
    “paySign”:info.paySign //微信签名
    },
    function(res){
    alert(res.err_msg)
    if(res.err_msg == “get_brand_wcpay_request:ok” ){
    // 使用以上方式判断前端返回,微信团队郑重提示:
    //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
    }
    });
    }

    //微信jsapi 支付 后端

    public function actionDakaDoneBywx()
    {
    	// if(input('type') == )
    	$order['user_id'] = $_SESSION['user_id'];
    	$order['pay_status'] = 1;
    	$order['pay_type'] = 'weixin';
    	$order['pay_out_trade_no'] = date('YmdHis',time()).$_SESSION['user_id'];
    	$order['pay_money'] = 1;
    	$order['sign_type'] = 3;
    	//微信支付参数构造
    	$param['appid'] = 'XXXXXXXXXXX';
    	$param['mch_id'] = '1497429492';
    	$param['nonce_str'] = $this->createNoncestr();
    	$param['body'] = "三级会员";
    	$param['out_trade_no'] = $order['pay_out_trade_no'];
    	$param['total_fee'] = 1;
    	$param['spbill_create_ip'] = $this->get_client_ip();
    	$param['notify_url'] = "https://XXXXXXXXXX";
    	$param['trade_type'] = 'JSAPI';
    	$param['sign_type'] = 'MD5';
    	$param['openid'] = M('wechat_user')->where(['ect_uid'=>$_SESSION['user_id']])->find()['openid'];
    	$param['sign'] = $this->getSign($param);
    	$xml = $this->arrayToXml($param);
    	$url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    	$data = $this->postXmlCurl($xml,$url);
    	$info = $this->xmlToArray($data);
    	if($info['return_code'] == "SUCCESS" && $info['result_code'] == "SUCCESS"){
    		$return['appId'] = $info['appid'];
    		$return['timeStamp'] = time();
    		$return['nonceStr'] = $info['nonce_str'];
    		$return['package'] = "prepay_id=".$info['prepay_id'];
    		$return['signType'] = 'MD5';
    		$pay_sign = $this->getSign($return);
    		$return['paySign'] = $pay_sign;
    		exit(json_encode(array('info'=>$return,'error_code'=>10000,'msg'=>'请求成功','ss'=>$info)));
    	}else{
    		exit(json_encode(array('error_code'=>10001,'msg'=>'请求失败')));
    	}
    }
    
    protected static function xmlToArray($xml){
    
        $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
    
        return $array_data;
    
    }
    
    private static function postXmlCurl($xml, $url, $second = 30)
    
    {
    
        $ch = curl_init();
    
        //设置超时
    
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
    
        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_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
    
        curl_setopt($ch, CURLOPT_TIMEOUT, 40);
    
        set_time_limit(0);
    
        //运行curl
    
        $data = curl_exec($ch);
    
        //返回结果
    
        if ($data) {
    
            curl_close($ch);
    
            return $data;
    
        } else {
    
            $error = curl_errno($ch);
    
            curl_close($ch);
    
            throw new WxPayException("curl出错,错误码:$error");
    
        }
    
    }
    
    protected function arrayToXml($arr){
    
        $xml = "<xml>";
    
        foreach ($arr as $key=>$val)
    
        {
    
            if (is_numeric($val)){
    
                $xml.="<".$key.">".$val."</".$key.">";
    
            }else{
    
                $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
    
            }
    
        }
    
        $xml.="</xml>";
    
        return $xml;
    
    }
    
    		/*
    
     *排序并格式化参数方法,签名时需要使用
    
     */
    
    protected function formatBizQueryParaMap($paraMap, $urlencode)
    
    {
    
        $buff = "";
    
        ksort($paraMap);
    
        foreach ($paraMap as $k => $v)
    
        {
    
            if($urlencode)
    
            {
    
                $v = urlencode($v);
    
            }
    
            //$buff .= strtolower($k) . "=" . $v . "&";
    
            $buff .= $k . "=" . $v . "&";
    
        }
    
        $reqPar = "";
    
        if (strlen($buff) > 0)
    
        {
    
            $reqPar = substr($buff, 0, strlen($buff)-1);
    
        }
    
        return $reqPar;
    
    }
    
    
    
    	/*
    
    * 对要发送到微信统一下单接口的数据进行签名
    
    */
    
    protected function getSign($Obj){
    
        foreach ($Obj as $k => $v){
    
            $param[$k] = $v;
    
        }
    
        //签名步骤一:按字典序排序参数
    
        ksort($param);
    
        $String = $this->formatBizQueryParaMap($param, false);
    
        //签名步骤二:在string后加入KEY
    
        $String = $String."&key=xxxxxxxxxxxxxxxx";//商户秘钥
    
        //签名步骤三:MD5加密
    
        $String = md5($String);
    
        //签名步骤四:所有字符转为大写
    
        $result_ = strtoupper($String);
    
        return $result_;
    
    }
    
    
    private function createNoncestr($length = 32)
    {
    	$chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
    	$str = '';
    
    	for ($i = 0; $i < $length; $i++) {
    		$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
    	}
    
    	return $str;
    }
    
    private function get_client_ip()
    {
    	if ($_SERVER['REMOTE_ADDR']) {
    		$cip = $_SERVER['REMOTE_ADDR'];
    	}
    	else if (getenv('REMOTE_ADDR')) {
    		$cip = getenv('REMOTE_ADDR');
    	}
    	else if (getenv('HTTP_CLIENT_IP')) {
    		$cip = getenv('HTTP_CLIENT_IP');
    	}
    	else {
    		$cip = 'unknown';
    	}
    
    	return $cip;
    }
    
    展开全文
  • 最近接触到一个项目,涉及到微信支付,搞微信开发这么久以来,还没搞过支付,之前也就搞...微信支付SDK,下载地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_13.登录微信支付平台https://pay.w...

    最近接触到一个项目,涉及到微信支付,搞微信开发这么久以来,还没搞过支付,之前也就搞过公众号发红包,感谢前辈们的探索,我看了他们的博文,让我少走了很多弯路。前期准备:1.微信认证服务号,并且开通了微信支付2.微信支付SDK,下载地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_13.登录微信支付平台https://pay.weixin.qq.com/index.php/account/api_cert下载支付证书方法步骤:1.demo文件处理(1)将官方的demo下载下来,文件名为WxpayAPI_php_v3,把这文件重命名为wxpay,为了后边书写目录方便;

    (2)打开lib文件夹下的WxPay.Api.PHP文件,在537行有一段curl网络请求配置代码:

    curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);

    curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验

    替换成:

    curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);

    curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验

    为了禁止 cURL 验证对等证书(peer's certificate)。

    (3)打开lib文件夹下的WxPay.Config.php文件,第25行开始,根据自己的账号完成基本信息设置;

    constAPPID ='公众账号APPID';

    constMCHID ='商户号';

    constKEY ='商户支付密钥';

    constAPPSECRET ='公众帐号secert';

    (4)打开lib文件夹下的WxPay.Notify.php文件,第79行的代码:

    if($needSign== true &&

    $this->GetReturn_code($return_code) =="SUCCESS")

    {

    $this->SetSign();

    }

    改成:

    if($needSign== true &&

    $this->GetReturn_code() =="SUCCESS")

    {

    $this->SetSign();

    }

    (5)打开cert证书目录,将里边的两个证书换成自己的支付证书。

    2.公众号后台设置

    (1)配置网页授权域名,我的域名是(xy.chuyin.ren);

    74be03550703bc6b284ac7eddfd30bca.png

    (1)配置支付授权目录,域名是(xy.chuyin.ren),我将demo放到此域名指向的目录的weixinopen/文件夹下,demo中jsapi.php文件位于example/目录下,所以支付授权目录为:xy.chuyin.ren/weixinopen/wxpay/example/

    ac893dec44d61aa52d8131b5babfa93a.png

    3.支付流程打开example目录下的jsapi.php文件,支付发起和处理,都是在这里完成。(1)获取用户openid

    之前配置好了自己的APPID和APPSecert,所以这里不用处理。

    //①、获取用户openid

    $tools=newJsApiPay();

    $openId=$tools->GetOpenid();

    这里首先初始化的一个JsApiPay()类得到一个对象,文件对应example/目录下的WxPay.JsApiPay.php,调用GetOpenid()方法,会自动获取自己的openID。

    (2)统一下单

    //②、统一下单

    $input=newWxPayUnifiedOrder();

    $input->SetBody("test");

    $input->SetAttach("test");

    $input->SetOut_trade_no(WxPayConfig::MCHID.date("YmdHis"));

    $input->SetTotal_fee("1");

    $input->SetTime_start(date("YmdHis"));

    $input->SetTime_expire(date("YmdHis", time() + 600));

    $input->SetGoods_tag("test");

    $input->SetNotify_url("http://paysdk.weixin.qq.com/example/notify.php");

    $input->SetTrade_type("JSAPI");

    $input->SetOpenid($openId);

    $order= WxPayApi::unifiedOrder($input);

    echo'统一下单支付单信息
    ';

    printf_info($order);

    $jsApiParameters=$tools->GetJsApiParameters($order);

    对应WxPay.Api.php的第24行的unifiedOrder()方法,配置订单信息和支付回调函数,这里需要修改几个参数:

    A. 商品名称:

    $input->SetBody("test");

    B. 订单号

    $input->SetOut_trade_no(WxPayConfig::MCHID.date("YmdHis"));

    C. 支付金额

    $input->SetTotal_fee("1");

    D. 支付验证链接

    设置为你的notify.php文件所在的位置,所以我这里设置为:http://xy.chuyin.ren/weixinopen/wxpay/example/notify.php

    也可以写其他地址,当然要在支付授权域名之下,支付成功之后就会自动回调到该链接指定的方法里边,可以在里边进行判断和数据库操作.

    $input->SetNotify_url("http://paysdk.weixin.qq.com/example/notify.php");

    E. 附加参数

    $input->SetAttach("test");

    附加参数,可填可不填,填写的话,里边字符串最好不要出现空格。这时候,点击支付应该就可以成功支付了。

    (3)发起支付

    //调用微信JS api 支付

    functionjsApiCall()

    {

    WeixinJSBridge.invoke(

    'getBrandWCPayRequest',

    <?php  echo $jsApiParameters; ?>,

    function(res){

    WeixinJSBridge.log(res.err_msg);

    alert(res.err_code+res.err_desc+res.err_msg);

    }

    );

    }

    functioncallpay()

    {

    if(typeofWeixinJSBridge =="undefined"){

    if( document.addEventListener ){

    document.addEventListener('WeixinJSBridgeReady', jsApiCall,false);

    }elseif(document.attachEvent){

    document.attachEvent('WeixinJSBridgeReady', jsApiCall);

    document.attachEvent('onWeixinJSBridgeReady', jsApiCall);

    }

    }else{

    jsApiCall();

    }

    }

    点击立即支付按钮调用的就是 callpay() 函数,他有会调用jsApiCall() 函数打开支付程序。

    6c276c47e095a6217cd10fb92f3a6c1d.png

    jsApiCall() 函数会监听每一步动作:

    63b94f9a9300340083d0a2ef67f18101.png

    res.err_msg 为get_brand_wcpay_request:cancel 表明前端判断的取消支付,es.err_msg 为get_brand_wcpay_request:ok 表明前端判断的支付成功,我们可以根据这个将支付跳转到成功页面。

    (4)支持成功回调

    通过前端jsApiCall()函数可以监听支付结果,但是这个并不可信。确认是否支付成功还是应当通过notify.php 处理业务逻辑。前边配置好了支付验证链接SetNotify_url(),支付完成后,微信服务器会根据链接自动请求你的notify.php文件,打开这个文件,其实这个文件最主要的代码就两行:

    $notify=newPayNotifyCallBack();

    $notify->Handle(false);

    由此跟踪到WxPay.Notify.php类文件的Handle()函数:

    /**

    *

    * 回调入口

    * @param bool $needSign  是否需要签名输出

    */

    final publicfunctionHandle($needSign= true)

    {

    $msg="OK";

    //当返回false的时候,表示notify中调用NotifyCallBack回调失败获取签名校验失败,此时直接回复失败

    $result= WxpayApi::notify(array($this,'NotifyCallBack'),$msg);

    if($result== false){

    $this->SetReturn_code("FAIL");

    $this->SetReturn_msg($msg);

    $this->ReplyNotify(false);

    return;

    } else{

    //该分支在成功回调到NotifyCallBack方法,处理完成之后流程

    $this->SetReturn_code("SUCCESS");

    $this->SetReturn_msg("OK");

    }

    $this->ReplyNotify($needSign);

    }

    主要代码:

    $result= WxpayApi::notify(array($this,'NotifyCallBack'),$msg);

    然后来到WxPay.Api.php文件的第411行,notify()函数:

    /**

    *

    * 支付结果通用通知

    * @param function $callback

    * 直接回调函数使用方法: notify(you_function);

    * 回调类成员函数方法:notify(array($this, you_function));

    * $callback  原型为:function function_name($data){}

    */

    publicstaticfunctionnotify($callback, &$msg)

    {

    //获取通知的数据

    $xml=$GLOBALS['HTTP_RAW_POST_DATA'];

    //file_put_contents('log.txt',$xml,FILE_APPEND);

    //如果返回成功则验证签名

    try {

    $result= WxPayResults::Init($xml);

    } catch (WxPayException $e){

    $msg=$e->errorMessage();

    returnfalse;

    }

    returncall_user_func($callback,$result);

    }

    这里面的$xml=$GLOBALS['HTTP_RAW_POST_DATA'],就是支付成功后用户返回给你的一个结果,他是一个xml格式的字符串。

    8d3e72a9b77e93e08169205bae646d7c.png

    我们可以将这里返回的xml数据记录下来,然后打开看看$out_trade_no就是在支付之前我自己设置的订单号码,$attach就是设置的附加参数。

    得到了这个订单号,然后我就直接在下面写支付成功后的逻辑了,比如改变数据库中的数据等等。

    这样 微信支付的 JsApi支付就大致分析完成了。

    3641581984f027112730b1f163cab19b.png

    展开全文
  • [CDATA[openid is invalid]]> </xml> 原因是,传有效过去不是的opendid。不小心看错了,把用户id 当做openid传过去了。   当统一下单成功,会返回以下格式的参数 (此图片来源于网络,如有侵权,请联系删除! )...
  • 微信JSAPI公众号支付是素材火群主提供的,支付成功后跳转到订单详情页,里面是微信支付成功后回调的数据,由第三方微信支付平台定时请求获取。
  • 微信支付-微信JSAPI支付

    千次阅读 2018-01-02 17:25:54
    关于微信,支付宝支付都做过了,但是很少有时间去写个博客,笔记啥的。话不多少,直接上代码吧! 此版本基于tp5(thinkphp5)的一个简易的微信支付类,目前可以正常支付哦,退款没有做,哈哈~~ 如下: Pay.php(/baby/...

    关于微信,支付宝支付都做过了,但是很少有时间去写个博客,笔记啥的。话不多少,直接上代码吧!

    此版本基于tp5(thinkphp5)的一个简易的微信支付类,目前可以正常支付哦,退款没有做,哈哈~~ 如下:

    Pay.php(/baby/extend/wx/Pay.php)

    <?php
    
    namespace wx;
    class Pay
    {
        /**
         * pay config
         * @var array
         */
        private $_payCfg = array(
            'appId' => 'your appId',
            'appSecret' => 'your appSecret',
            'mchId' => 'your mchId',#商户号
            'mchSecret' => 'your mchSecret',#商户号secret
        );
    
        /**
         * redirect_url
         * @var
         */
        private $_redirectUrl;
    
        public function __construct($redirectUrl = NULL)
        {
            if (!empty($redirectUrl)) {
                $this->_redirectUrl = $redirectUrl;
            }
        }
    
        /**
         * 通过redirectUri获取授权信息
         * @return mixed
         */
        public function getAuthInfo()
        {
            //通过appId获取code
            $redirectUri = urlencode($this->_redirectUrl);
            $codeUrl = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' . $this->_payCfg['appId'] . '&redirect_uri=' . $redirectUri . '&response_type=code&scope=snsapi_base&state=YQJ#wechat_redirect';
    
            if (empty($_REQUEST['code'])) {
                header('Location:' . $codeUrl);
                exit;
            }
    
            //通过code换取网页授权信息
            $curl = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' . $this->_payCfg['appId'] . '&secret=' . $this->_payCfg['appSecret'] . '&code=' . $_REQUEST['code'] . '&grant_type=authorization_code';
            $res = $this->_curlGetReq($curl);
            $authInfo = '';
            if ($res['tag']) {
                if (is_object($res['msg'])) {
                    $formatRes = (array)$res['msg'];
                    $authInfo = array(
                        'accessToken' => !empty($formatRes['access_token']) ? $formatRes['access_token'] : '',
                        'expiresIn' => !empty($formatRes['expires_in']) ? $formatRes['expires_in'] : '',
                        'refreshToken' => !empty($formatRes['refresh_token']) ? $formatRes['refresh_token'] : '',
                        'openId' => !empty($formatRes['openid']) ? $formatRes['openid'] : '',
                        'scope' => !empty($formatRes['snsapi_base']) ? $formatRes['snsapi_base'] : '',
                    );
                }
            }
            return $authInfo;
        }
    
        /**
         * 下单支付
         * @param $param
         * @return array|string
         */
        public function toPay($param)
        {
            $body = empty($param['body']) ? 'xoxoxo' : $param['body'];
            $orderSn = empty($param['orderSn']) ? $this->generateOrderNum() : $param['orderSn'];
            $totalFee = empty($param['fee']) ? 0.01 : $param['fee'];
            $openId = empty($param['openId']) ? '' : $param['openId'];
    
            //统一下单参数构造
            $unifiedOrder = array(
                'appid' => $this->_payCfg['appId'],
                'mch_id' => $this->_payCfg['mchId'],
                'nonce_str' => $this->getNonceStr(),
                'body' => $body,
                'out_trade_no' => $orderSn,
                'total_fee' => $totalFee*100,
                'spbill_create_ip' => $this->getClientIp(),
                'notify_url' => 'https://www.baidu.com',//todo 你的支付回调url
                'trade_type' => 'JSAPI',
                'openid' => $openId
            );
            $unifiedOrder['sign'] = $this->makeSign($unifiedOrder);
    
            //请求数据,统一下单
            $xmlData = $this->toXml($unifiedOrder);
            $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
            $res = $this->postXmlCurl($url, $xmlData);
            if (!$res) {
                return array('status' => 0, 'msg' => "Can't connect the server");
            }
            $content = $this->toArr($res);
    
            if (!empty($content) && is_array($content)) {
                if (!empty($content['result_code'])) {
                    if ($content['result_code'] == 'FAIL') {
                        return array('status' => 0, 'msg' => $content['err_code'] . ':' . $content['err_code_des']);
                    }
                }
                if (!empty($content['return_code'])) {
                    if ($content['return_code'] == 'FAIL') {
                        return array('status' => 0, 'msg' => $content['return_msg']);
                    }
                }
    
                $time = time();
                settype($time, "string");
                $resData = array(
                    'appId' => strval($content['appid']),
                    'nonceStr' => strval($content['nonce_str']),
                    'package' => 'prepay_id=' . strval($content['prepay_id']),
                    'signType' => 'MD5',
                    'timeStamp' => $time
                );
                $resData['paySign'] = $this->makeSign($resData);
            }
            return json_encode($resData);
        }
    
        /**
         * 产生随机字符串,不长于32位
         * @param int $length
         * @return string
         */
        public 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;
        }
    
        /**
         * 生成签名
         * @param $unifiedOrder
         * @return string
         */
        public function makeSign($unifiedOrder)
        {
            //签名步骤一:按字典序排序参数
            ksort($unifiedOrder);
            $string = $this->toUrlParams($unifiedOrder);
            //签名步骤二:在string后加入KEY
            $string = $string . "&key=" . $this->_payCfg['mchSecret'];
            //签名步骤三:MD5加密
            $string = md5($string);
            //签名步骤四:所有字符转为大写
            $result = strtoupper($string);
            return $result;
        }
    
        /**
         * 格式化参数格式化成url参数
         * @param $unifiedOrder
         * @return string
         * @internal param $unifiedOrder
         */
        public function toUrlParams($unifiedOrder)
        {
            $buff = "";
            foreach ($unifiedOrder as $k => $v) {
                if ($k != "sign" && $v != "" && !is_array($v)) {
                    $buff .= $k . "=" . $v . "&";
                }
            }
            $buff = trim($buff, "&");
            return $buff;
        }
    
        /**
         * 输出xml字符
         * @param $unifiedOrder
         * @return string
         */
        public function toXml($unifiedOrder)
        {
            if (!is_array($unifiedOrder) || count($unifiedOrder) <= 0) exit('数组异常');
    
            $xml = "<xml>";
            foreach ($unifiedOrder as $key => $val) {
                if (is_numeric($val)) {
                    $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
                } else {
                    $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
                }
            }
            $xml .= "</xml>";
            return $xml;
        }
    
        /**
         * 将xml转为array
         * @param $xml
         * @return mixed
         */
        public function toArr($xml)
        {
            //将XML转为array,禁止引用外部xml实体
            libxml_disable_entity_loader(true);
            return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        }
    
        /**
         * curl get request
         * @param $url
         * @return array
         */
        public function _curlGetReq($url)
        {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_TIMEOUT, 10);
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_HEADER, false);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            curl_setopt($ch, CURLOPT_HEADER, false);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    
            $res = curl_exec($ch);
            $error = curl_error($ch);
            curl_close($ch);
    
            if ($res === false) {
                return array('tag' => false, 'msg' => $error);
            }
            return array(
                'tag' => true,
                'msg' => json_decode($res)
            );
        }
    
        /**
         * 以post方式提交xml到对应的接口url
         * @param $xml
         * @param $url
         * @return mixed
         */
        public function postXmlCurl($url, $xml)
        {
            $ch = curl_init();
            //设置超时
            curl_setopt($ch, CURLOPT_TIMEOUT, 10);
            //如果有配置代理这里就设置代理
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);//严格校验
            //设置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);
            //返回结果
            if ($data) {
                curl_close($ch);
                return $data;
            } else {
                $error = curl_errno($ch);
                curl_close($ch);
                exit("curl出错,错误码:$error");
            }
        }
    
        /**
         * 获取ip
         * @return bool
         */
        public function getClientIp()
        {
            $ip = false;
            if (!empty($_SERVER["HTTP_CLIENT_IP"]) && '127.0.0.1' != $_SERVER["HTTP_CLIENT_IP"]) {
                $ip = $_SERVER["HTTP_CLIENT_IP"];
            }
            if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
                $ips = explode(", ", $_SERVER['HTTP_X_FORWARDED_FOR']);
                if ($ip) {
                    array_unshift($ips, $ip);
                    $ip = FALSE;
                }
                for ($i = 0; $i < count($ips); $i++) {
                    //echo $ips[$i].'<br>';
                    if (!preg_match('/^(10|172\.16|192\.168)\./', $ips[$i])) {
                        $ip = $ips[$i];
                        break;
                    }
                }
            }
            return (empty($ip) || preg_match('/[^0-9^\.]+/', $ip)) ? $_SERVER['REMOTE_ADDR'] : $ip;
            //return ($ip ? $ip : $_SERVER['REMOTE_ADDR']);
        }
    
        /**
         * 生成16位订单号
         * @return string
         */
        public function generateOrderNum()
        {
            return $order_number = date('Ymd') . substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
        }
    }
    简单的支付类已经OK了,现在差调用层了,代码如下:

    Test.php(/baby/application/index/controller/Test.php)

    <?php
    namespace app\index\controller;
    use think\Controller;
    use think\Request;
    class Test extends Controller
    {
    
        public function index(){
            $redirectUri = 'https://www.baidu.com/test.html';
            $payObj = new \wx\Pay($redirectUri);
    
            $authInfo = $payObj->getAuthInfo();
            if(!empty($authInfo['openId'])){
                $payInfo = array(
                    'body'=>'xoxoxoxo',
                    'fee'=>0.01,
                    'openId'=>$authInfo['openId'],
                );
    
                $payRes = $payObj->toPay($payInfo);
    
                $this->assign('payRes',$payRes);
    
            }
            return $this->fetch('index/test');
        }
        //异步通知没有做,后续补充~
        public function notify(){
            exit('回调');
        }
    }
    调用层的代码也已经OK了,最后就差模板了,如下:

    test.html(/baby/application/index/view/index/test.html)

    <html>
    <head>
    	<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
    	<meta name="viewport" content="width=device-width, initial-scale=1"/>
    	<title>微信JSAPI支付</title>
    	<script type="text/javascript">
            function jsApiCall()
            {
                WeixinJSBridge.invoke(
                    'getBrandWCPayRequest',{$payRes},
                    function(res){
                        if(res.err_msg == "get_brand_wcpay_request:ok"){
                            alert("支付成功!");
                            window.location.href="http://www.baidu.com";
                        }else if(res.err_msg == "get_brand_wcpay_request:cancel"){
                            alert("用户取消支付!");
                        }else{
                            alert("支付失败!");
                        }
                    }
                );
            }
    
            function callpay()
            {
                if (typeof WeixinJSBridge == "undefined"){
                    if( document.addEventListener ){
                        document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
                    }else if (document.attachEvent){
                        document.attachEvent('WeixinJSBridgeReady', jsApiCall);
                        document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
                    }
                }else{
                    jsApiCall();
                }
            }
    	</script>
    
    </head>
    <body>
    <br/>
    <font color="#9ACD32"><b>该笔订单支付金额为<span style="color:#f00;font-size:50px">1分</span>钱</b></font><br/><br/>
    <font color="#9ACD32"><b><span style="color:#f00;font-size:50px;margin-left:40%;">1分</span>钱也是爱</b></font><br/><br/>
    <div align="center">
    	<button style="width:210px; height:50px; border-radius: 15px;background-color:#FE6714; border:0px #FE6714 solid; cursor: pointer;  color:white;  font-size:16px;" type="button" οnclick="callpay()" >剁手吧</button>
    </div>
    </body>
    </html>


     关键在微信公众号平台要配置好,说实在的,初次去配置,确实费劲,通读下微信官方文档吧!有问题@me.





    展开全文
  • 最近接触到一个项目,涉及到微信支付,搞微信开发这么久以来,还没搞过支付,之前也就搞...微信支付SDK,下载地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_13.登录微信支付平台https://pay.w...
  • 微信JSAPI支付

    千次阅读 2020-03-21 08:55:42
    JSAPI支付是用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块完成支付。 2.基本设置 2.1 支付授权目录 请确保实际支付时的请求目录与后台配置的目录一致,否则将无法...
  • 微信JSAPI支付_1

    2019-09-18 16:16:11
    微信JSAPI支付 模式 JSAPI支付是用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块完成支付。应用场景有: ◆ 用户在微信公众账号内进入商家公众号,打开某个主页面,...
  • 上一篇PHP微信公众号JSAPI网页支付(上)中讲到了公众号平台的相关设置以及支付的大致流程。这一篇重点讲支付后,异步接受回调通知,以及处理后同步通知微信服务器。首先梳理下整个jsapi支付的流程1.网页授权获取用户...
  • vue接入微信jsapi支付

    千次阅读 2020-01-03 14:51:51
    在h5中接入微信jsapi支付 JSAPI支付是用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块完成支付。应用场景有: ◆ 用户在微信公众账号内进入商家公众号,打开某个主页面...
  • Java 微信jsapi支付

    2020-06-28 11:17:20
    spring boot微信jsapi支付话不多说,撸起袖子就是干,下面上源码pom.xml配置文件 resources/wx.properties配置类service(WechatPayService)上impl(WechatPayServiceImpl)之前还是先上一个获取IP的工具类和返回工具类...
  • 在使用前可以先看上面的微信扫码支付和H5支付的文章,本文主要介绍微信JSAPI支付,在微信内拉起支付; 开发注意事项: 1、在开发前请先确认回调的域名是否加入了JS安全域名,IP白名单,微信公众平台和微信支付...
  • 微信商户平台(pay.weixin.qq.com)设置您的JSAPI支付支付目录,设置路径:商户平台–>产品中心–>开发配置,如图7.7所示。JSAPI支付在请求支付的时候会校验请求来源是否有在商户平台做了配置,所以必须确.....
  • 微信 JSAPI 支付

    2020-05-23 20:21:14
    一、申请微信公众号、开通微信支付,通过【APPID】将两者关联,具体操作步骤参考:点击查看 二、在公众号管理后台设置...七、生成 JSAPI 支付需要的参数 八、用户输完支付密码,前台轮询订单状态,后台在 NOTIFY_U...
  • 记录新人微信jsapi支付 1基本的我上一篇扫码支付已经说过了,首先需要开启商户的jsapi支付就不多说了,jsapi支付还需要将你的域名加入到商户和公众号的授权支付域名,具体请观看文档 2有一点需要注意的是看下图,他...
  • 微信jsapi支付对接

    千次阅读 2020-04-01 14:23:30
    微信jsapi对接首先需要获取code传给后台以获取用户的openid 刚进入页面需要判断是否是在微信app内部打开你页面的连接 var is_weixin = (function(){return navigator.userAgent.toLowerCase().indexOf('...
  • 前面写了一篇 JAVA后端调用微信支付“统一下单”接口实现微信二维码扫码支付 ,好事成双嘛,想起了自己还做过微信JSAPI支付,所以一并分享了。 官方对微信JSAPI的应用场景的解释是: 官方的使用场景介绍是:...
  • 微信 JSAPI 支付 微信内部起调H5支付 支付完成发送公众号消息模板 JSAPI支付 openID是必传的,所以这里先获取用户openID,想要获取openID,首先我们要拿到code,再获取openID JS: <script> // 强制关注...
  • tp5.0 微信jsapi支付

    2020-12-14 17:46:00
    tp5.0 微信jsapi支付流程 1、下载官方sdk包放在extend目录下 2、在公众号里面关联商户号,在商户号里面配置域名 3、在Wxpay.Config.php这个文件里面把你的公众号APPID、APPSECRET,商户号MCHID,自己设置的商户秘钥...
  • C# .NETMVC 微信JSAPI支付

    2020-08-26 20:01:57
    C# .NET MVC微信JSAPI支付 经过本人不断翻找资料和百度终于结合一些大佬的经验和思路弄出来一个MVC的微信支付了。 再弄微信支付之前我们需要先有一个商户号,并且开通了微信支付的JSAPI支付功能,也需要申请微信...
  • 接入微信JSAPI支付的时候遇到的问题: 1.检查后台返回给前端的微信公众号支付数据是否齐全,因为是要验签的,所以少一个参数都会出现问题. 2.在后台请求微信统一下单接口的时候(trade_type=JSAPI),微信用户的openid为必...
  • 微信JSAPI支付回调

    2017-01-25 18:18:00
    在经历了千幸万苦之,填完了所有的JSAPI支付的坑后(微信JSAPI支付 跟 所遇到的那些坑),好不容易调起了微信支付接口,看到了亲爱的支付页面,支付成功后发现自己还有个叫做微信回调的忘了处理,内心一万只草泥马在...
  • 微信扫码支付微信JSAPI支付

    千次阅读 2018-11-28 09:14:44
    项目中用到了PC端扫码支付微信公众号的JSAPI支付,在此记录, 以免小伙伴被网上的‘拿来主义’给误导。 使用框架THINKPHP5, 类文件保存在extend/payment 文件夹内。 包含功能:扫码支付(采用先生成预支付订单...
  • 微信JSAPI错误填坑

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,736
精华内容 1,894
关键字:

微信jsapi支付openid