php开发实现微信小程序支付功能

/**
 * 构建微信支付
 * @return \Response
 */
public function WxPay()
{
    $input  = Request::all();
    $openId = $input['openId'] ?? null;
    
    //判断金额是否为正整数
    $input['total_fee'] = $input['total_fee']*100;
    if (!preg_match("/^[1-9][0-9]*$/", $input['total_fee'])) {
        return '金额错误';
    }

    //验证订单
    $order_id = intval($input['order_id']);
    $order = Order::where('id',$order_id)->first();
    if(!$order){
        return '订单不存在';
    }

    $notify_url = "回调地址";

    $data = [
        'out_trade_no' => $order->order_code,
        'total_fee'    => $input['total_fee'],
        'openid'       => $input['openId'],
        'body'         => $input['body'] ?? null,
        'created_at'   => Carbon::now(),
        'updated_at'   => Carbon::now(),
    ];
    $data['notify_url'] = $notify_url;
    //调用微信支付统一下单
    $result = $this->unifiedOrder($data);
    // 请求失败
    if (!$result) {
        //请求失败
    }
    if ($result['return_code'] === 'FAIL' || $result['result_code'] === 'FAIL') {
       //调用出错
    }
   
    //调起支付数据签名字段
    $timeStamp = time();
    $appid     = $result['appid'];
    $nonce_pay = str_shuffle($result['nonce_str']);//随机字符串
    $package   = $result['prepay_id'];
    $signType  = "MD5";
    $key       = Common::KEY;
    $stringPay = "appId=" . $appid . "&nonceStr=" . $nonce_pay . "&package=prepay_id=" . $package . "&signType=" . $signType . "&timeStamp=" . $timeStamp . "&key=" . $key;
    $paySign   = strtoupper(md5($stringPay));

    //这些参数需要返回给小程序组件使用,弹出支付页面
    $pay_data = array(
        'nonceStr'  => $nonce_pay,
        'package'   => "prepay_id=" . $package,
        'timeStamp' => (string)$timeStamp,
        'paySign'   => $paySign,
        'signType'  => $signType
    );
    return $pay_data;
}


 /**
 * 小程序 统一下单方法
 * @param $data
 * array(
 * 'out_trade_no' => 商户订单号,
 * 'total_fee' => 总金额,
 * 'openid' => 用户标识,
 * 'body' => 商品描述,
 * )
 * @return bool|mixed
 */
public function unifiedOrder(array $data)
{
    $common                     = (new Common);
    $params['appid']            = $common::SHOP_ID;
    $params['mch_id']           = $common::MCH_ID;
    $params['nonce_str']        = $common->GenRandomString();//随机字符串
    $params['body']             = $data['body'];//商品描述
    $params['out_trade_no']     = $data['out_trade_no'];//商户订单号
    $params['total_fee']        = $data['total_fee'];//总金额
    $params['spbill_create_ip'] = $_SERVER['REMOTE_ADDR'];//终端IP
    $params['notify_url']       = $data['notify_url'];//通知地址
    $params['trade_type']       = 'JSAPI';//交易类型
    $params['openid']           = $data['openid'];//用户标识
    //$this->params['detail']           = $data['detail'] ?? null;//商品详情
    //$this->params['attach']           = $data['attach'] ?? null;//附加数据
    ksort($params);
    //获取签名数据
    $sign           = $common->Sign($params);
    $params['sign'] = $sign;//签名
    $xml            = $common->DataToXml($params);
    $response = $common->PostXmlCurl($xml, 'https://api.mch.weixin.qq.com/pay/unifiedorder');
    if (!$response) {
        return false;
    }

    return $common->XmlToData($response);
}

common.php 文件内容入下:

 /**
 * 产生一个指定长度的随机字符串,并返回给用户
 * @param  $len //产生字符串的长度
 * @return string 随机字符串
 */
public 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;
}

 /**
 * 签名 $data要先排好顺序
 * @param $data
 * @return string
 */
public function Sign($data)
{
    ksort($data);
    $stringA = '';
    foreach ($data as $key => $value) {
        if (!$value) continue;
        if ($stringA) $stringA .= '&' . $key . "=" . $value;
        else $stringA = $key . "=" . $value;
    }
    $wx_key         = $this::KEY;//申请支付后有给予一个商户账号和密码,登陆后自己设置的key
    $stringSignTemp = $stringA . '&key=' . $wx_key;
    return strtoupper(md5($stringSignTemp));
}

 /**
 * 将xml转为array
 * @param string $xml
 * return array
 * @return bool|mixed
 */
public function XmlToData($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
 *
 * @return bool|string
 */
public function DataToXml($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;
}

 /**
 * 以post方式提交xml到对应的接口url
 *
 * @param string $xml 需要post的xml数据
 * @param string $url url
 * @param bool $useCert 是否需要证书,默认不需要
 * @param int $second url执行超时时间,默认30s
 * @return bool|string
 * @throws
 */
public 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, $useCert);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $useCert ? 2 : 0);
    //设置header
    curl_setopt($ch, CURLOPT_HEADER, FALSE);
    //要求结果为字符串且输出到屏幕上
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    if ($useCert == true) {
        //TODO 以下两种方式需选择一种
        /*------- --第一种方法,cert 与 key 分别属于两个.pem文件--------------------------------*/
        //使用证书:cert 与 key 分别属于两个.pem文件
        //默认格式为PEM,可以注释
        curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
        curl_setopt($ch, CURLOPT_SSLCERT, '绝对路径');
        //默认格式为PEM,可以注释
        curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
        curl_setopt($ch, CURLOPT_SSLKEY, '绝对路径');
        /**
         * 补充 当找不到ca根证书的时候还需要rootca.pem文件
         * TODO 注意,微信给出的压缩包中,有提示信息:
         *      由于绝大部分操作系统已内置了微信支付服务器证书的根CA证书,
         *      2018年3月6日后, 不再提供CA证书文件(rootca.pem)下载
         */
        //curl_setopt($ch, CURLOPT_CAINFO,self::APICLIENT_CA);

        /*----------第二种方式,两个文件合成一个.pem文件----------------------------------------*/
        //curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/all.pem');

    }
    //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;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,490评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,581评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,830评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,957评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,974评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,754评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,464评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,847评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,995评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,137评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,819评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,482评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,023评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,149评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,409评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,086评论 2 355