注意事项:

1、微信退款需要双向证书

2、微信金额 需要 乘以100 ,以分为单位。

<?php
class pays{
    /**
     * 获取微信App支付参数
     * @param $userId 支付用户账号
     * @param $taskId 支付订单号
     * @param $out_trade_no 网站唯一订单号
     * @param $total_fee 支付金额
     * @return array 参数
     */
    public function getPayAlipay($userId,$taskId,$out_trade_no,$total_fee){
        //添加支付记录
        pdo_insert("taskpaylog",array(
            "account"=>$userId,
            "taskId"=>$taskId,
            "outTradeNo"=>$out_trade_no,
            "payType"=>"alipay",//支付方式,Alipay 阿里,WeChat 微信
            "createtime"=>time()
        ));

        vendor('alipay.aop.AopClient');
        vendor('alipay.aop.SignData');
        vendor('alipay.aop.request.AlipayTradeAppPayRequest');

        $aop = new \AopClient ();
        $aop->gatewayUrl = "https://openapi.alipay.com/gateway.do";//"https://openapi.alipay.com/gateway.do"; https://openapi.alipaydev.com/gateway.do

        $aop->appId = "***************************************";//“应用ID,填写你的APPID”;
        $aop->rsaPrivateKey = "***************************************";//"商户私钥,您的原始格式RSA私钥()";
        $aop->alipayrsaPublicKey = "***************************************";

        $aop->apiVersion = '1.0';
        $aop->signType = "RSA2";
        $aop->postCharset = 'UTF-8';
        $aop->format = "json";

        $appRequest = new \AlipayTradeAppPayRequest();
        $bizcontent = json_encode([
            'body' => '测试支付', //订单描述
            'subject' => '项目名称',  //订单标题
            'timeout_express' => '30m',//超时时间
            'out_trade_no' => $out_trade_no, //商户网站唯一订单号
            'total_amount' => "{$total_fee}", //订单总金额
            'product_code' => 'QUICK_MSECURITY_PAY', //固定值
        ]);
        $url = "http://{$_SERVER['HTTP_HOST']}/notify/aliPay.php";
        $appRequest->setNotifyUrl($url);  //设置异步通知地址
        $appRequest->setBizContent($bizcontent);
        $response = $aop->sdkExecute($appRequest);
        return array("code"=>0,"result"=>$response);
        //return htmlspecialchars($response);
    }

    /**
     * 调用支付宝app支付退款
     * @param $out_trade_no
     * @param $refund_fee
     * @return string
     */
    public function tkAlipay($out_trade_no,$refund_fee){
        vendor('alipay.aop.AopClient');
        vendor('alipay.aop.SignData');
        vendor('alipay.aop.request.AlipayTradeRefundRequest');


        $aop = new \AopClient ();
        $aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
        $aop->appId = "***************************************";//“应用ID,填写你的APPID”;
        $aop->rsaPrivateKey = "***************************************";//"商户私钥,您的原始格式RSA私钥()";
        $aop->alipayrsaPublicKey = "***************************************";

        $aop->apiVersion = '1.0';
        $aop->signType = "RSA2";
        $aop->postCharset = 'UTF-8';
        $aop->format = "json";
        $request = new \AlipayTradeRefundRequest ();


        //"\"trade_no\":\"2014112611001004680073956707\"," . //支付宝交易号,和商户订单号不能同时为空 特殊可选
        $request->setBizContent("{" .
            "\"out_trade_no\":\"{$out_trade_no}\"," .  //订单支付时传入的商户订单号,不能和 trade_no同时为空。 特殊可选
            "\"refund_amount\":\"{$refund_fee}\"," . //需要退款的金额,该金额不能大于订单金额,单位为元,支持两位小数     必选
            "\"refund_reason\":\"订单取消-退款\"" . //退款的原因说明    正常退款 可选 最后的“,”逗号去掉
            "}");
        $result = $aop->execute($request);
        $responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
        $resultCode = $result->$responseNode->code;
        if(!empty($resultCode) && $resultCode == 10000){
            return "SUCCESS";
        } else {
            return "FAIL";
        }
    }

    /**
     * 获取支付宝App支付参数
     * @param $userId 支付用户账号
     * @param $taskId 支付订单号
     * @param $out_trade_no 网站唯一订单号
     * @param $total_fee 支付金额
     * @return array 参数
     */
    //获取微信支付参数
    public function getPayWechat($userId,$taskId,$out_trade_no,$total_fee){
        //添加支付记录
        pdo_insert("taskpaylog",array(
            "account"=>$userId,
            "taskId"=>$taskId,
            "outTradeNo"=>$out_trade_no,
            "payType"=>"WeChat",//支付方式,Alipay 阿里,WeChat 微信
            "createtime"=>time()
        ));

        $key = '***************************************';//key为商户平台设置的密钥key
        $appid = '***************************************';//应用ID
        $mch_id = '***************************************';//商户号

        $nonce_str = mt_rand(100000, 999999);//随机字符串
        $body = '测试支付';//商品描述
        $total_fee = $total_fee * 100;//总金额
        $spbill_create_ip = $_SERVER['REMOTE_ADDR'];//终端IP
        $out_trade_no = $out_trade_no;//商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一。详见商户订单号
        $notify_url = 'http://'.$_SERVER['HTTP_HOST'].'/notify/wechatPay.php';//通知地址
        $trade_type = 'APP';//交易类型

        //https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
        $stra = "appid=".$appid."&body=".$body."&mch_id=".$mch_id."&nonce_str=".$nonce_str."¬ify_url=".$notify_url."&out_trade_no=".$out_trade_no."&spbill_create_ip=".$spbill_create_ip."&total_fee=".$total_fee."&trade_type=".$trade_type;
        $str = $stra."&key=".$key;
        $sign = strtoupper(md5($str));
        $datas = "<xml>
       <appid>$appid</appid>
       <body>$body</body>
       <mch_id>$mch_id</mch_id>
       <nonce_str>$nonce_str</nonce_str>
       <notify_url>$notify_url</notify_url>
       <out_trade_no>$out_trade_no</out_trade_no>
       <spbill_create_ip>$spbill_create_ip</spbill_create_ip>
       <total_fee>$total_fee</total_fee>
       <trade_type>$trade_type</trade_type>
       <sign>$sign</sign>
    </xml>";

        //统一下单接口
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        // 创建一个新cURL资源
        $ch = curl_init();
        // 设置URL和相应的选项
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $datas);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        // 抓取URL并把它传递给浏览器
        $package = curl_exec($ch);
        //关闭cURL资源,并且释放系统资源
        curl_close($ch);

        $xml = simplexml_load_string($package, 'SimpleXMLElement', LIBXML_NOCDATA);
        $data = json_decode(json_encode($xml),TRUE);

        //https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12&index=2
        if($data['return_code'] == 'SUCCESS') {
            $time = time();
            $packages = "Sign=WXPay";
            $stra = "appid=".$data['appid']."&noncestr=".$data['nonce_str']."&package=".$packages."&partnerid=".$data['mch_id']."&prepayid=".$data['prepay_id']."×tamp=".$time;
            $str = $stra."&key=".$key;
            $signs = strtoupper(md5($str));

            return array(
                'code' => 0,
                'result' => array(
                    'appid' => $data['appid'],
                    'partnerid' => $data['mch_id'],
                    'mch_id' => $data['mch_id'],
                    'prepayid' => $data['prepay_id'],
                    'package' => $packages,
                    'noncestr' => $data['nonce_str'],
                    'timestamp' => ''.$time,
                    'sign' => $signs,
                )
            );
        }else {
            return array(
                'status' => 1,
                'return_msg' => $data
            );
        }
    }

    /**
     * 微信app支付退款函数
     * @param $out_trade_no string 退款的订单
     * @param $out_refund_no  string 退款单号
     * @param $total_fee int 已支付金额
     * @param $refund_fee int 退款金额
     * @return mixed 退款返回参数
     */
    public function tkWechat($out_trade_no,$out_refund_no,$total_fee,$refund_fee){
        $refund_fee *= 100;
        $total_fee *= 100;

        $key = '***************************************';//key为商户平台设置的密钥key
        $appid = '***************************************';//应用ID
        $mch_id = '***************************************';//商户号

        $nonce_str = ''.strval(mt_rand(100000, 999999));//随机字符串

        $stra = "appid=".$appid."&mch_id=".$mch_id."&nonce_str=".$nonce_str."&out_refund_no=".$out_refund_no."&out_trade_no=".$out_trade_no."&refund_fee=".$refund_fee."&total_fee=".$total_fee;
        $str = $stra ."&key=" . $key;
        $sign = strtoupper(md5($str));//签名

        $dataXML = "<xml>
       <appid>$appid</appid>
       <mch_id>$mch_id</mch_id>
       <nonce_str>$nonce_str</nonce_str>
       <out_refund_no>$out_refund_no</out_refund_no>
       <out_trade_no>$out_trade_no</out_trade_no>
       <refund_fee>$refund_fee</refund_fee>
       <total_fee>$total_fee</total_fee>
       <sign>$sign</sign>
    </xml>";

        $url = "https://api.mch.weixin.qq.com/secapi/pay/refund";//退款接口链接
        $ch = curl_init();
        //超时时间
        curl_setopt($ch,CURLOPT_TIMEOUT,30);
        //这里设置代理,如果有的话
        //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);

        // 设置证书
        curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'pem');
        curl_setopt($ch, CURLOPT_SSLCERT, 'notify/cert/apiclient_cert.pem');
        curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'pem');
        curl_setopt($ch, CURLOPT_SSLKEY, 'notify/cert/apiclient_key.pem');
//        curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'pem');
//        curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/WxPay/cert/rootca.pem');

        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $dataXML);
        $package = curl_exec($ch);
        curl_close($ch);

        $xml = simplexml_load_string($package, 'SimpleXMLElement', LIBXML_NOCDATA);
        $data = json_decode(json_encode($xml),TRUE);
        if($data['return_code'] == 'SUCCESS'){
            return "SUCCESS";
        } else {
            return "FAIL";
        }
    }
}