app支付宝微信支付

class PayController extends Yaf_Controller_Abstract
{
    //微信接口API URL前缀
    const API_URL_PREFIX = 'https://api.mch.weixin.qq.com';
    //下单地址URL
    const UNIFIEDORDER_URL = "/pay/unifiedorder";
    //支付秘钥
    protected $key;

    /**
     * @GetUrl      快捷支付请求HTML
     * ================================================
     * @GET
     * @Type        登录类型 AliPay:支付宝,
     * @Money       充值金额
     */
    public function GetOrderAction($name = "Stringer")
    {

        // 传入值过滤
        if (preg_match("/^\d{1,9}(\.\d{1,2})?$/", trim($_POST['Money'])) && in_array($_POST['Type'], ['WeiXin', 'AliPay'])) {
            // 获取用户登录数据
            $UserID = true;
            //$UserID = HostID();
            // 判断用户是否登录

            if ($UserID) {
                // 初始化
                $Time = time();
                $IntIP = IntIp();
                $Type = $_POST['Type'];
                $Category = $_POST['Category'];
                $Key = RandomStr(32, 2);
                $Money = trim($_POST['Money']);
                $HostID = HostID();
                if (!$HostID) {
                    $HostID = $_POST['UserID'];
                }
                $SaveMoney = (int)($Money * 100);
                $Session = Yaf_Session::getInstance();
                $OverTime = (int)Yaconf::get("TaskYun.AliPay.OverTime");

                $AliOver = ceil($OverTime / 60);
                $SQlTile = $Time + $OverTime;
                // 生成订单号
                $OrderID = OrderGenerate($HostID, 1);


                // 保存该Key
                $Session->{$Key} = json_encode(array(
                    "IP" => IntIp(),
                    "Money" => $Money,
                    "Name" => $Type,
                    "Time" => $Time,
                ));

                $Title = "落地达人网支付宝充值";
                // 支付宝描述
                $Comment = "落地达人网钱包支付宝充值" . $Money . "元";
                if ($Type == "WeiXin") {
                    $ChannelID = 2;
                } else {
                    $ChannelID = 1;
                }
                //获取余额
                $PayWallete = UserWallete($HostID);
                $balance=$PayWallete['Balance'];

                // 保存相关数据到数据库中
                $PayOrder = new MySqlModel("INSERT INTO `PayOrder` VALUES ('$OrderID', '1', '$IntIP','$HostID','0','$Time','$balance', '$ChannelID', '1')");
                $PayOrder->WrRrows();

                // 保存充值订单
                $PayRecharge = new MySqlModel("INSERT INTO `PayRecharge` VALUES ('$OrderID', '$ChannelID', '', '0', '$HostID', '$SaveMoney', '1', '$Time', '0', '$SQlTile', '')");
                $auto_id = $PayRecharge->WrRrows();;
                if (!$auto_id) {
                    exit(json_encode(array("Status" => "false", "Content" => "写入充值订单表失败")));
                }

                //Category等于2时为项目押金
                if ((int)$Category == 2) {
                    //执行人ID
                    $ExecuteUserID = $_POST["ExecuteUserID"];

                    //项目ID
                    $ProjectID = $_POST['ProjectID'];
                    //查询项目详情
                    //查看是不是自己的项目在项目发布表中查找;
                    $Project_obj = new MySqlModel("SELECT `FounderID`,`ProjectName` FROM `PublishProject`WHERE `ProjectID`=$ProjectID AND `FounderID` = $HostID");
                    $Project_obj = $Project_obj->WrOneAssoc();
                    if ($ExecuteUserID && is_numeric($ExecuteUserID) && $Project_obj ) {
                        $Remark="项目【".$Project_obj['ProjectName']."】启动款";
                        // 保存项目款订单
                        $PayInside = new MySqlModel("INSERT INTO `PayInside` VALUES ('$OrderID', '$HostID', '$ExecuteUserID', '0', '$SaveMoney', '$SaveMoney', '$Time', '1', '$ProjectID', '$Remark')");
                        $auto_id = $PayInside->WrRrows();
                        if (!$auto_id) {
                            exit(json_encode(array("Status" => "200", "Content" => "写入资金流水表失败")));
                        }
                    } else {
                        exit(json_encode(array("Status" => "false", "Content" => "项目执行人能为空")));
                    }
                }

                switch ($Type) {
                    case "AliPay":
                        // 请求支付宝支付
                        echo $this->UnifiedOrderAliPay($OrderID, $Title, $Comment, $Money, $Category, $AliOver);
                        // 结束
                        return true;
                        break;
                    case "WeiXin":
                        echo $this->UnifiedOrderWeiXin($OrderID, $Title, $Comment, $Money, $Category, $OverTime);
                        return true;
                        break;
                    default:
                        // 其余的
                        $ReturnText = "充值类型暂不支持";
                }
            } else {
                $ReturnText = "请登录后再执行充值操作";
            }
        } else {
            $ReturnText = "传入参数有误或您输入了一亿及以上的金额";
        }
        return $ReturnText;

    }


    //支付宝统一下单方法
    public function UnifiedOrderAliPay($OrderID, $Title, $Comment, $Money, $Key, $OverTime)
    {
        // 自动加载类
        $Path = Yaconf::get("TaskYun.Home") . "AppButll/library/AliPay/";
        require_once $Path . "AopClient.php";
        require_once $Path . "request/AlipayTradeAppPayRequest.php";
        $AppID = Yaconf::get("TaskYun.AliPay");
        $aop = new AopClient;
        $aop->gatewayUrl = "https://openapi.alipay.com/gateway.do";
        $aop->appId = $AppID['AppID'];
        $aop->rsaPrivateKey = $AppID['PrivateKey'];
        $aop->format = "json";
        $aop->charset = "UTF-8";
        $aop->signType = "RSA2";
        $aop->alipayrsaPublicKey = $AppID['PublicKey'];
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
        $request = new AlipayTradeAppPayRequest();
        //SDK已经封装掉了公共参数,这里只需要传入业务参数
        $bizcontent = json_encode([
            'body' => $Comment,
            'subject' => $Title,
            'out_trade_no' => $OrderID,//此订单号为商户唯一订单号
            'total_amount' => $Money,//保留两位小数
            'product_code' => 'QUICK_MSECURITY_PAY',
            "passback_params" => urlencode($Key),
            "timeout_express" => $OverTime . "m",
        ]);
        //设置回调地址
        //$request->setNotifyUrl("https://chenlongzhen.cn/ceshi.php");
        $request->setNotifyUrl("https://www.rw.cn/App/Pay/NotifyAliPay.html");
        $request->setBizContent($bizcontent);
        //这里和普通的接口调用不同,使用的是sdkExecute
        $response = $aop->sdkExecute($request);
        //htmlspecialchars是为了输出到页面时防止被浏览器将关键参数html转义,实际打印到日志以及http传输不会有这个问题
        ReturnEcho("true", $response);
    }


    /**
     * 微信下单方法
     * @param   $params 下单参数
     */
    public function UnifiedOrderWeiXin($OrderID, $Title, $Comment, $Money, $Key, $OverTime)
    {
        $WeiXinPay = Yaconf::get("TaskYun.WeiXinPay");
        $this->key = $WeiXinPay['key'];
        $this->params['appid'] = $WeiXinPay['appid'];
        $this->params['mch_id'] = $WeiXinPay['mch_id'];
        $this->params['nonce_str'] = $this->genRandomString();
        $this->params['body'] = $Title;
        $this->params['out_trade_no'] = $OrderID;
        $this->params['total_fee'] = $Money * 100;
        $this->params['spbill_create_ip'] = $_SERVER['REMOTE_ADDR'];
        $this->params['notify_url'] = "https://www.rw.cn/App/Pay/NotifyWeixin.html";
        //$this->params['notify_url'] = "https://chenlongzhen.cn/ceshi.php";
        $this->params['trade_type'] = "APP";
        $this->params['detail'] = $Comment;
        $this->params['attach'] = "$Key";
        //获取签名数据

        $this->params['sign'] = $this->MakeSign($this->params);
        $xml = $this->data_to_xml($this->params);
        $response = $this->postXmlCurl($xml, self::API_URL_PREFIX . self::UNIFIEDORDER_URL);
        if (!$response) {
            return false;
        }
        $result = $this->xml_to_data($response);
        if (!empty($result['result_code']) && !empty($result['err_code'])) {
            $result['err_msg'] = $this->error_code($result['err_code']);
        }
        //将返回的数据二次签名
        $resignData = array(
            'appid' => $result['appid'],
            'partnerid' => $result['mch_id'],
            'prepayid' => $result['prepay_id'],
            'noncestr' => $this->genRandomString(),
            'timestamp' => time(),
            'package' => 'Sign=WXPay'
        );

        $sign = $this->MakeSign($resignData);
        $resignData['sign'] = $sign;
        $resignData['return_code'] = $result['return_code'];

        return json_encode($resignData);


    }

    //支付宝异步通知方法
    public function NotifyAliPayAction($name = "Stringer")
    {
        //$data = json_decode($_POST['name'], true);
        // 自动加载类


        $Path = Yaconf::get("TaskYun.Home") . "AppButll/library/AliPay/";
        require_once $Path . "AopClient.php";
        require_once $Path . "request/AlipayTradeAppPayRequest.php";
        // 初始化
        $Time = time();
        $SavarIP = getIP();
        $aop = new AopClient();

        $AliPay = Yaconf::get("TaskYun.AliPay");

        // 载入公钥
        $aop->alipayrsaPublicKey = $AliPay['PublicKey'];
        // 校验支付宝传入数据
        $Result = $aop->rsaCheckV1($_POST, "", "RSA2");

        // 判断数据是否正确
        if ($Result) {
            // 校验无误,查询是否有此订单

            $AliNo = $_POST['trade_no'];
            $Status = $_POST['trade_status'];
            $LddrNo = $_POST['out_trade_no'];
            $ToMoney = $_POST['buyer_pay_amount'] * 100;
            // 查询目标渠道是否有该交易
            $NewRecharge = new MySqlModel("SELECT `UserID`, `Money`, `Type`, `OverTime` FROM `PayRecharge` WHERE `OrderID` = '$LddrNo' LIMIT 1");
            $PayRecharge = $NewRecharge->WrOneAssoc();

            // 判断订单是否存在
            if ($PayRecharge) {

                // 提取详情
                $Money = $PayRecharge['Money'];
                $Type = (int)$PayRecharge['Type'];
                $HostID = $PayRecharge['UserID'];

                // 判断金额是否正确
                if ($ToMoney == $Money) {

                    // 判断状态是否
                    switch ($Status) {
                        case 'WAIT_BUYER_PAY':
                            // 等待卖家付款中,无处理
                            break;
                        case 'TRADE_CLOSED':
                            // 未付款交易超时关闭,或支付完成后全额退款,判断原本是什么状态
                            if ($Type == 2) {
                                // 判断是否为退款,本系统不支持退款!!警报
                                if (isset($_POST['out_biz_no'])) {
                                    // 获取警报数据
                                    $LDRRUrl = yaconf::get("TaskYun.LddrHost");
                                    $PhoneList = yaconf::get("TaskYun.RootPhone");
                                    // 保存日志
                                    $NewPay = new MySqlModel("INSERT INTO `PayErrorLog` VALUES ('', '$HostID', '$LddrNo', '$SavarIP', '非法退款,本系统没置退款功能', '<{[Log]}>')", array(
                                        "Log" => json_encode($_POST)
                                    ));
                                    $LogID = $NewPay->InsertId();
                                    // 发送警报信息
                                    $SMSReturn = new MessageModel("SMS_82780011");
                                    $MaileError = $SMSReturn->send_verify($PhoneList, array(
                                        "Url" => $LDRRUrl . "Pay/PayLog.html?ID=" . $LogID,
                                        "Name" => "非法退款",
                                        "Time" => $Time,
                                    ));
                                    return false;
                                }
                            }
                            // 修改订单为超时终止状态
                            $NewUpdate = new MySqlModel("UPDATE `PayRecharge` SET `Type` = '3' WHERE `OrderID` = '$LddrNo' LIMIT 1");
                            $NewUpdate->WrRrows();
                            break;
                        case 'TRADE_SUCCESS':
                            if ((int)$Type == 2) {
                                //exit("此订单已完成过支付!");
                            }

                            $NewUpdate = new MySqlModel("UPDATE `PayRecharge` SET `Type` = '2',`ChannelOrder`='$AliNo'  WHERE `OrderID` = '$LddrNo'");
                            $NewUpdate->WrRrows();
                            // 获取用户余额
                            $PayWallete = UserWallete($HostID);
                            //print_r($PayWallete);
                            // 添加用户余额,并保存
                            $category = urldecode($_POST['passback_params']);

                            switch ((int)$category) {
                                case 1:
                                    UpUserWallete($HostID, (int)$PayWallete['Balance'] + (int)$ToMoney, $PayWallete['Freeze']);
                                    //将交易流水号写入数据库跟新订单状态
                                    break;
                                case 2:
                                    $Project_id = new MySqlModel("SELECT  `Link` FROM `PayInside` WHERE `OrderID` = '$LddrNo' LIMIT 1");
                                    $Project_id = $Project_id->WrAssoc();
                                    RunProject($HostID, $PayWallete['Freeze'], $PayWallete['Balance'], $Time, $Project_id, 1);
                                    //将交易流水号写入数据库跟新订单状态

                                    $NewUpdate = new MySqlModel("UPDATE `PayInside` SET `Type` = '2' WHERE `OrderID` ='$LddrNo'");
                                    $NewUpdate->WrRrows();
                            }

                            //计算充值后的余额
                            $Balance=$PayWallete['Balance']+$ToMoney;
                            // 为用户账户添加资金
                            $NewUpdate = new MySqlModel("UPDATE `PayOrder` SET `Diversity` = '$ToMoney',`Balance` = '$Balance', `Type` = '2' WHERE `OrderID` ='$LddrNo'");
                            $NewUpdate->WrRrows();

                            break;
                        case 'TRADE_FINISHED':
                            // 交易结束,不可退款
                            $NewUpdate = new MySqlModel("UPDATE `PayRecharge` SET `Type` = '4' WHERE `OrderID` = '$LddrNo'");
                            $NewUpdate->WrRrows();
                            break;
                        default:
                            // 其他
                            ReturnEcho(189);
                    }

                    echo "success";

                } else {
                    // 链接有误
                    ReturnEcho(1);
                }

            } else {
                // 订单不存在
                ReturnEcho(187);
            }
        } else {
            // 校验有误
            ReturnEcho(186);
        }


    }


    //微信支付异步通知方法
    public function NotifyWeixinAction()
    {
        //$postXml = $GLOBALS["HTTP_RAW_POST_DATA"];    // 接受通知参数;
        $postXml = file_get_contents("php://input");
        //$postXml = $_POST['name'];
        if (empty($postXml)) {
            return false;
        }
        $postObj = $this->xml_to_data($postXml);      // 调用解析方法,将xml数据解析成对象

        if ($postObj === false) {
            return false;
        }
        if (!empty($postObj['return_code'])) {
            if ($postObj["return_code"] == 'FAIL') {
                return false;
            }
        }
        $WeiXinPay = Yaconf::get("TaskYun.WeiXinPay");
        $this->key = $WeiXinPay['key'];
        $data = $this->object2array($postObj);//对象转成数组
        unset($data['sign']);
        // 拼装数据进行第三次签名
        $sign = $this->MakeSign($data);        // 获取签名

        /** 将签名得到的sign值和微信传过来的sign值进行比对,如果一致,则证明数据是微信返回的。 */
        if ($sign == $postObj["sign"]) {
            //$HostID = HostID();
            //查看订单信息
            $NewRecharge = new MySqlModel("SELECT `UserID`, `Money`, `Type`, `OverTime` FROM `PayRecharge` WHERE `OrderID` = " . $postObj["out_trade_no"] . " LIMIT 1");
            $PayRecharge = $NewRecharge->WrOneAssoc();

            if ($PayRecharge) {
                $HostID = $PayRecharge['UserID'];
                $Money = $PayRecharge['Money'];
                $Type = $PayRecharge['Type'];
                $out_trade_no = $postObj["out_trade_no"];
                $total_fee = $postObj["total_fee"];
                if ((int)$Type == 2) {
                    exit("此订单已完成过支付!");
                }

                if ((int)$Money !== (int)$postObj["total_fee"]) {
                    exit("金额异常!");
                }
                $NewUpdate = new MySqlModel("UPDATE `PayRecharge` SET `Type` = '2',`ChannelOrder`=" . $postObj["transaction_id"] . "  WHERE `OrderID` = '$out_trade_no'");
                $NewUpdate->WrRrows();
                // 获取用户余额
                $PayWallete = UserWallete($HostID);
                // 添加用户余额,并保存
                switch ((int)$postObj['attach']) {
                    case 1:

                        UpUserWallete($HostID, (int)$PayWallete['Balance'] + (int)$postObj["total_fee"], $PayWallete['Freeze']);
                        //将交易流水号写入数据库跟新订单状态
                        break;
                    case 2:

                        $Time = time();
                        $Project_id = new MySqlModel("SELECT  `Link` FROM `PayInside` WHERE `OrderID` = '$out_trade_no' LIMIT 1");
                        $Project_id = $Project_id->WrAssoc();

                        RunProject($HostID, $PayWallete['Freeze'], $PayWallete['Balance'], $Time, $Project_id, 1);

                        //将交易流水号写入数据库跟新订单状态
                        $NewUpdate = new MySqlModel("UPDATE `PayInside` SET `Type` = '2' WHERE `OrderID` = '$out_trade_no'");
                        $NewUpdate->WrRrows();
                }
                //计算充值后的余额
                $Balance=$PayWallete['Balance']+$postObj["total_fee"];
                // 为用户账户添加资金
                $NewUpdate = new MySqlModel("UPDATE `PayOrder` SET `Diversity` ='$total_fee',`Balance`='$Balance', `Type` = '2' WHERE `OrderID` ='$out_trade_no'");
                $NewUpdate->WrRrows();

                $reply = "<xml>
                    <return_code><![CDATA[SUCCESS]]></return_code>
                    <return_msg><![CDATA[OK]]></return_msg>
                </xml>";
                echo $reply;      // 向微信后台返回结果。

                exit;

            } else {
                exit("订单不存在!");
            }

        } else {
            exit("数据异常!");
        }

    }


    /**
     * 产生一个指定长度的随机字符串,并返回给用户
     * @param type $len 产生字符串的长度
     * @return string 随机字符串
     */
    private function genRandomString($len = 32)
    {
        $chars = array(
            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
            "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
            "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G",
            "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
            "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2",
            "3", "4", "5", "6", "7", "8", "9"
        );
        $charsLen = count($chars) - 1;
        // 将数组打乱
        shuffle($chars);
        $output = "";
        for ($i = 0; $i < $len; $i++) {
            $output .= $chars[mt_rand(0, $charsLen)];
        }
        return $output;
    }


    /**
     * 生成签名
     * @return 签名
     */
    public function MakeSign($params)
    {
        //签名步骤一:按字典序排序数组参数
        ksort($params);
        $string = $this->ToUrlParams($params);
        //签名步骤二:在string后加入KEY
        $string = $string . "&key=" . $this->key;
        //签名步骤三:MD5加密
        $string = md5($string);
        //签名步骤四:所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }


    /**
     * 将参数拼接为url: key=value&key=value
     * @param   $params
     * @return  string
     */
    public function ToUrlParams($params)
    {
        $string = '';
        if (!empty($params)) {
            $array = array();
            foreach ($params as $key => $value) {
                $array[] = $key . '=' . $value;
            }
            $string = implode("&", $array);
        }
        return $string;
    }

    /**
     * 将xml转为array
     * @param string $xml
     * return array
     */
    public function xml_to_data($xml)
    {
        if (!$xml) {
            return false;
        }
        //将XML转为array
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $data;
    }

    /**
     * 输出xml字符
     * @param   $params     参数名称
     * return   string      返回组装的xml
     **/
    public function data_to_xml($params)
    {
        if (!is_array($params) || count($params) <= 0) {
            return false;
        }
        $xml = "<xml>";
        foreach ($params as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

    //curl发送请求
    private function postXmlCurl($xml, $url, $useCert = false, $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, 2);
        //设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        if ($useCert == true) {
            //设置证书
            //使用证书:cert 与 key 分别属于两个.pem文件
            curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
            //curl_setopt($ch,CURLOPT_SSLCERT, WxPayConfig::SSLCERT_PATH);
            curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
            //curl_setopt($ch,CURLOPT_SSLKEY, WxPayConfig::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;
        }
    }


    //把对象转成数组
    function object2array($array)
    {
        if (is_object($array)) {
            $array = (array)$array;
        }
        if (is_array($array)) {
            foreach ($array as $key => $value) {
                $array[$key] = $this->object2array($value);
            }
        }
        return $array;
    }


    //用户退出登录
    function logError($object)
    {
        error_log(date("[Y-m-d H:i:s]") . " -[" . $_SERVER['REQUEST_URI'] . "] :" . $object . "/n", 3, "../php_err.log");

    }
}

猜你喜欢

转载自blog.csdn.net/qq_26959879/article/details/80064044