PHP APP端微信支付

前面已经写了手机APP支付宝支付,今天再把手机APP微信支付补上,前期的准备工作在这里就不多说了,可以参考微信支付开发文档,一定要仔细阅读开发文档,可以让你少踩点坑;准备工作完成后就是配置参数,调用统一下单接口,支付后异步回调三部曲啦;

1.我封装好的一个支付类文件,多余的东西都去除掉了,并且把配置参数放到了这个支付类中,只需要修改Weixinpayandroid方法内的几个参数就可以直接复制使用:

class Wxpayandroid
{
    //参数配置
    public $config = array(
                ‘appid‘ => "",    /*微信开放平台上的应用id*/
                ‘mch_id‘ => "",   /*微信申请成功之后邮件中的商户id*/
                ‘api_key‘ => "",    /*在微信商户平台上自己设定的api密钥 32位*/
            );

    //服务器异步通知页面路径(必填)
    public $notify_url = ‘‘;

    //商户订单号(必填,商户网站订单系统中唯一订单号)
    public $out_trade_no = ‘‘;
    //商品描述(必填,不填则为商品名称)
    public $body = ‘‘;

    //付款金额(必填)
    public $total_fee = 0;

    //自定义超时(选填,支持dhmc)
    public $time_expire = ‘‘;

    private $WxPayHelper;

    public function Weixinpayandroid($total_fee,$tade_no)
    {
        $this->total_fee = intval($total_fee * 100);//订单的金额 1元
        $this->out_trade_no = $tade_no;// date(‘YmdHis‘) . substr(time(), - 5) . substr(microtime(), 2, 5) . sprintf(‘%02d‘, rand(0, 99));//订单号
        $this->body = ‘wxpay‘;//支付描述信息
        $this->time_expire = date(‘YmdHis‘, time() + 86400);//订单支付的过期时间(eg:一天过期)
        $this->notify_url = "http://www.ceshi.com/notifyandroid";//异步通知URL(更改支付状态)
        //数据以JSON的形式返回给APP
        $app_response = $this->doPay();
        if (isset($app_response[‘return_code‘]) && $app_response[‘return_code‘] == ‘FAIL‘) {
            $errorCode = 100;
            $errorMsg = $app_response[‘return_msg‘];
            $this->echoResult($errorCode, $errorMsg);
        } else {
            $errorCode = 0;
            $errorMsg = ‘success‘;
            $responseData = array(
                ‘notify_url‘ => $this->notify_url,
                ‘app_response‘ => $app_response,
            );
            $this->echoResult($errorCode, $errorMsg, $responseData);
        }
    }

    //接口输出
    function echoResult($errorCode = 0, $errorMsg = ‘success‘, $responseData = array())
    {
        $arr = array(
            ‘errorCode‘ => $errorCode,
            ‘errorMsg‘ => $errorMsg,
            ‘responseData‘ => $responseData,
        );
         exit(json_encode($arr));      //exit可以正常发送给APP json数据
        // return json_encode($arr);  //在TP5中return这个json数据,APP接收到的是null,无法正常吊起微信支付
    }

    function getVerifySign($data, $key)
    {
        $String = $this->formatParameters($data, false);
        //签名步骤二:在string后加入KEY
        $String = $String . "&key=" . $key;
        //签名步骤三:MD5加密
        $String = md5($String);
        //签名步骤四:所有字符转为大写
        $result = strtoupper($String);
        return $result;
    }

    function formatParameters($paraMap, $urlencode)
    {
        $buff = "";
        ksort($paraMap);
        foreach ($paraMap as $k => $v) {
            if($k=="sign"){
                continue;
            }
            if ($urlencode) {
                $v = urlencode($v);
            }
            $buff .= $k . "=" . $v . "&";
        }
        $reqPar;
        if (strlen($buff) > 0) {
            $reqPar = substr($buff, 0, strlen($buff) - 1);
        }
        return $reqPar;
    }

    /**
     * 得到签名
     * @param object $obj
     * @param string $api_key
     * @return string
     */
    function getSign($obj, $api_key)
    {
        foreach ($obj as $k => $v)
        {
            $Parameters[strtolower($k)] = $v;
        }
        //签名步骤一:按字典序排序参数
        ksort($Parameters);
        $String = $this->formatBizQueryParaMap($Parameters, false);
        //签名步骤二:在string后加入KEY
        $String = $String."&key=".$api_key;
        //签名步骤三:MD5加密
        $result = strtoupper(md5($String));
        return $result;
    }

    /**
     * 获取指定长度的随机字符串
     * @param int $length
     * @return Ambigous <NULL, string>
     */
    function getRandChar($length){
       $str = null;
       $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
       $max = strlen($strPol)-1;
       for($i=0;$i<$length;$i++){
            $str.=$strPol[rand(0,$max)];//rand($min,$max)生成介于min和max两个数之间的一个随机整数
       }
       return $str;
    }

    /**
     * 数组转xml
     * @param array $arr
     * @return string
     */
    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;
    }

    /**
     * 以post方式提交xml到对应的接口url
     *
     * @param string $xml  需要post的xml数据
     * @param string $url  url
     * @param bool $useCert 是否需要证书,默认不需要
     * @param int $second   url执行超时时间,默认30s
     * @throws WxPayException
     */
    function postXmlCurl($xml, $url, $second=30, $useCert=false, $sslcert_path=‘‘, $sslkey_path=‘‘)
    {
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
        curl_setopt($ch,CURLOPT_URL, $url);
        //设置header
        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);

        if($useCert == true){
            curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
            curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验
            //设置证书
            //使用证书:cert 与 key 分别属于两个.pem文件
            curl_setopt($ch,CURLOPT_SSLCERTTYPE,‘PEM‘);
            curl_setopt($ch,CURLOPT_SSLCERT, $sslcert_path);
            curl_setopt($ch,CURLOPT_SSLKEYTYPE,‘PEM‘);
            curl_setopt($ch,CURLOPT_SSLKEY, $sslkey_path);
        }
        //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);
            return false;
        }
    }

    /**
     * 获取当前服务器的IP
     * @return Ambigous <string, unknown>
     */
    function get_client_ip()
    {
        if (isset($_SERVER[‘REMOTE_ADDR‘])) {
            $cip = $_SERVER[‘REMOTE_ADDR‘];
        } elseif (getenv("REMOTE_ADDR")) {
            $cip = getenv("REMOTE_ADDR");
        } elseif (getenv("HTTP_CLIENT_IP")) {
            $cip = getenv("HTTP_CLIENT_IP");
        } else {
            $cip = "127.0.0.1";
        }
        return $cip;
    }

    /**
     * 将数组转成uri字符串
     * @param array $paraMap
     * @param bool $urlencode
     * @return string
     */
    function formatBizQueryParaMap($paraMap, $urlencode)
    {
        $buff = "";
        ksort($paraMap);
        foreach ($paraMap as $k => $v)
        {
            if($urlencode)
            {
               $v = urlencode($v);
            }
            $buff .= strtolower($k) . "=" . $v . "&";
        }
        $reqPar;
        if (strlen($buff) > 0)
        {
            $reqPar = substr($buff, 0, strlen($buff)-1);
        }
        return $reqPar;
    }

    /**
     * XML转数组
     * @param unknown $xml
     * @return mixed
     */
    function xmlToArray($xml)
    {
        //将XML转为array
        $array_data = json_decode(json_encode(simplexml_load_string($xml, ‘SimpleXMLElement‘, LIBXML_NOCDATA)), true);
        return $array_data;
    }
    public function chkParam()
    {
        //用户网站订单号
        if (empty($this->out_trade_no)) {
            die(‘out_trade_no error‘);
        }
        //商品描述
        if (empty($this->body)) {
            die(‘body error‘);
        }
        if (empty($this->time_expire)){
            die(‘time_expire error‘);
        }
        //检测支付金额
        if (empty($this->total_fee) || !is_numeric($this->total_fee)) {
            die(‘total_fee error‘);
        }
        //异步通知URL
        if (empty($this->notify_url)) {
            die(‘notify_url error‘);
        }
        if (!preg_match("#^http:\/\/#i", $this->notify_url)) {
            $this->notify_url = "http://" . $_SERVER[‘HTTP_HOST‘] . $this->notify_url;
        }
        return true;
    }

    /**
     * 生成支付(返回给APP)
     * @return boolean|mixed
     */
    public function doPay() {
        //检测构造参数
        $this->chkParam();
        return $this->createAppPara();
    }

    /**
     * APP统一下单
     */
    private  function createAppPara()
    {
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";

        $data["appid"]        = $this->config[‘appid‘];//微信开放平台审核通过的应用APPID
        $data["body"]         = $this->body;//商品或支付单简要描述
        $data["mch_id"]       = $this->config[‘mch_id‘];//商户号
        $data["nonce_str"]    = $this->getRandChar(32);//随机字符串
        $data["notify_url"]   = $this->notify_url;//通知地址
        $data["out_trade_no"] = $this->out_trade_no;//商户订单号
        $data["spbill_create_ip"] = $this->get_client_ip();//终端IP
        $data["total_fee"]        = $this->total_fee;//总金额
        $data["time_expire"]      = $this->time_expire;//交易结束时间
        $data["trade_type"]       = "APP";//交易类型
        $data["sign"]             = $this->getSign($data, $this->config[‘api_key‘]);//签名
        $xml        = $this->arrayToXml($data);
        $response   = $this->postXmlCurl($xml, $url);
        //将微信返回的结果xml转成数组
        $responseArr = $this->xmlToArray($response);
        if(isset($responseArr["return_code"]) && $responseArr["return_code"]==‘SUCCESS‘){
            return  $this->getOrder($responseArr[‘prepay_id‘]);
        }
        return $responseArr;
    }

    /**
     * 执行第二次签名,才能返回给客户端使用
     * @param int $prepayId:预支付交易会话标识
     * @return array
     */
    public function getOrder($prepayId)
    {
        $data["appid"]      = $this->config[‘appid‘];
        $data["noncestr"]   = $this->getRandChar(32);
        $data["package"]    = "Sign=WXPay";
        $data["partnerid"]  = $this->config[‘mch_id‘];
        $data["prepayid"]   = $prepayId;
        $data["timestamp"]  = time();
        $data["sign"]       = $this->getSign($data, $this->config[‘api_key‘]);
        $data["packagestr"] = "Sign=WXPay";
        return $data;
    }

    /**
     * 异步通知信息验证
     * @return boolean|mixed
     */
    public function verifyNotify()
    {
        $xml = isset($GLOBALS[‘HTTP_RAW_POST_DATA‘]) ? $GLOBALS[‘HTTP_RAW_POST_DATA‘] : ‘‘;
        if(!$xml){
            return false;
        }
        $wx_back = $this->xmlToArray($xml);
        if(empty($wx_back)){
            return false;
        }
        $checkSign = $this->getVerifySign($wx_back, $this->config[‘api_key‘]);
        if($checkSign=$wx_back[‘sign‘]){
            return $wx_back;
        }else{
            return false;
        }
    }
}

  

2.创建控制器定义统一下单接口和支付后的异步回调接口:

  //异步通知接口
    public function notifyandroid()
    {
        $wxpayandroid = new \Wxpayandroid;     //实例化微信支付类
        $verify_result = $wxpayandroid->verifyNotify();
        if ($verify_result[‘return_code‘]==‘SUCCESS‘ && $verify_result[‘result_code‘]==‘SUCCESS‘) {
          //商户订单号
          $out_trade_no = $verify_result[‘out_trade_no‘];
          //交易号
          $trade_no     = $verify_result[‘transaction_id‘];
          //交易状态
          $trade_status = $verify_result[‘result_code‘];
          //支付金额
          $total_fee    = $verify_result[‘total_fee‘]/100;
          //支付过期时间
          $pay_date     = $verify_result[‘time_end‘];
          $order = new Order();
          $ret = $order->getOrderN2($out_trade_no); //获取订单信息
          $total_amount=$ret[‘money‘];
          if ($total_amount==$total_fee) {
              // 验证成功 修改数据库的订单状态等 $result[‘out_trade_no‘]为订单号
              //此处写自己的逻辑代码
          }
            exit(‘<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>‘);
        }else{
            exit(‘<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[ERROR]]></return_msg></xml>‘);
        }
    }

    //调用统一下单接口生成预支付订单并把数据返回给APP
    public function wxpayandroid(Request $request)
    {
        $param = $request->param(); //接收值

        $tade_no = $param[‘orderCode‘];
        $order = new Order();   //实例化订单
        $ret = $order->getOrderN2($tade_no);  //查询订单信息
        $total_fee = $ret[‘money‘]; //订单总金额

        $wxpayandroid = new \Wxpayandroid;     //实例化微信支付类
        $res = $wxpayandroid->Weixinpayandroid($total_fee,$tade_no);    //调用weixinpay方法

    }

封装一个支付类文件,并把配置参数放到支付类内,再定义控制器创建两个方法,这样两步就可以把手机APP微信支付搞定啦。

原文地址:https://www.cnblogs.com/52lnamp/p/9208724.html

时间: 2024-08-02 21:45:10

PHP APP端微信支付的相关文章

PHP app 唤起微信支付 获取链接【项目实例】

public function weixin_params_data(){  $data  = $this->ApiData();   //获取接口访问的数据 //$_type = $post_data['type']; if(!$data['out_trade_no']){ systemmess('0','参数错误'); } $WxPayConfig = array( 'APPID'=>'wxc123456789', 'MCHID'=>'123456', 'KEY'=>'KEY'

PHP TP5框架-手机APP端支付宝支付

最近应业务需求,做了支付宝支付和微信支付,今天分享一下手机端app支付宝支付对接流程,实际开发过程是前后端分离,前端调用后端API接口,实现功能返回数据,我所用的跨挤啊为TP5,大致可以分为四步: 1.在蚂蚁金服开放平台创建应用,签约商户,生成应用公钥和私钥: 2.配置统一下单支付参数: 3.整合支付宝demo类文件: 4.创建Alipay支付类,类内创建两个方法(alipay_app:统一下单方法和alipay_notify:支付成功异步回调方法); 第一步主要是在蚂蚁金服开放平台登录你的支付

移动端微信支付和支付宝支付

说明: 此项目是h5+app项目,不是此项目,请勿参考 context是this curPayType是支付的方式 ordercode当前订单号 1 Alipay(curPayType,ordercode){2 if(curPayType){//微信支付 3 context.$fetch.post('url',{ordercode}).then((res)=>{//url为请求微信支付的接口 4 console.log('微信支付',res.data) 5 var self = plus.web

IOS APP端京东支付集成

京东支付没有现成的SDK, 使用的是加载html.因此,在集成京东支付的时候,我们使用webView来进行加载显示支付的页面. 京东支付需要传递多个参数才能拉起支付页面,那么我们怎么样获得和传递参数呢? 1.我们需要与自己的后台进行交互,通过网络请求,获取到拉起支付页面所需要的参数,并将参数解析成字符串进行保存. 2.在选择京东支付方式之后, 跳转到一个由Viewcontroller控制webView的场景下,将webView的delegate指向当前的ViewController.将获取到的参

微信支付开发(APP)的各种坑,.net和iOS的各种陷阱,解决.net调用下单接口提示无权限,解决iOS跳转到微信支付页面中间只有一个确定按钮

直入主题之前,请容我吐槽一下微*的官方东西:ASDFQ%#$%$#$%^[email protected]#$%DSFQ#$%.......:吐槽玩了!大家心照就好. 要完成手机APP跳转到微信的APP进行微信支付,需要进行如下操作: 1.先去微信的开放平台(http://open.weixin.qq.com)进行开发者账号的注册. 2.新建一个APP应用,然后填写必填信息提交审核. 3.进入APP应用,在接口信息中,进行申请“获得微信支付能力”的功能,期间会提交相关的公司营业信息证明等. 通过

微信支付(APP)集成时碰到的问题(.net提示“无权限”、iOS跳转到微信支付页面中间只有一个“确定”按钮)

直入主题之前,请容我吐槽一下微*的官方东西:ASDFQ%#$%$#$%^[email protected]#$%DSFQ#$%.......:吐槽玩了!大家心照就好. 要完成手机APP跳转到微信的APP进行微信支付,需要进行如下操作: 1.先去微信的开放平台(http://open.weixin.qq.com)进行开发者账号的注册. 2.新建一个APP应用,然后填写必填信息提交审核. 3.进入APP应用,在接口信息中,进行申请“获得微信支付能力”的功能,期间会提交相关的公司营业信息证明等. 通过

【第十二篇】微信支付(APP)集成时碰到的问题(.net提示“无权限”、iOS跳转到微信支付页面中间只有一个“确定”按钮)(转)

直入主题之前,请容我吐槽一下微*的官方东西:ASDFQ%#$%$#$%^[email protected]#$%DSFQ#$%.......:吐槽玩了!大家心照就好. 要完成手机APP跳转到微信的APP进行微信支付,需要进行如下操作: 1.先去微信的开放平台(http://open.weixin.qq.com)进行开发者账号的注册. 2.新建一个APP应用,然后填写必填信息提交审核. 3.进入APP应用,在接口信息中,进行申请“获得微信支付能力”的功能,期间会提交相关的公司营业信息证明等. 通过

利用微信支付的订单查询接口可以在APP 中提高支付的可靠性

最近公司有一个应用,用户可以在微信公众号上面下单,也可以在APP 中下单. 当用户在公共号上面下单时,微信支付成功可以返回微信支付单号,但是在APP 中用户微信支付时,个别时候会出现用户没有付款成功,却在支付后的回调逻辑中执行了订单支付成功的逻辑. 显然在APP中微信支付的这种回调逻辑是不可靠的. (1)首先说明下为什么要拿到微信支付订单号 微信支付订单号是微信系统在支付成功后返回的订单号,比如这样的订单号:4007322001201705049543255213, 拿到这个订单号可以调用微信查

php微信支付接口开发程序(一)

阅读对象 本文阅读对象:商户系统(在线购物平台.人工收银系统.自动化智能收银系统或其他)集成微信支付涉及的技术架构师,研发工程师,测试工程师,系统运维工程师. 支付模式 1. 刷卡支付 刷卡支付是用户展示微信钱包内的“刷卡条码/二维码”给商户系统扫描后直接完成支付的模式.主要应用线下面对面收银的场景. 2. 扫码支付 扫码支付是商户系统按微信支付协议生成支付二维码,用户再用微信“扫一扫”完成支付的模式.该模式适用于PC网站支付.实体店单品或订单支付.媒体广告支付等场景. 3. 公众号支付 公众号