function weixin_pay($openid, $money, $path, $title, $info, $out_num = '') { //拉取基础信息 //获取支付基础信息,这里的话可以可以将微信支付对应的参数放到mysql里面 //这里是查询微信小程序的appid,切记appid要与商户id关联 $appid = Db::name('config_data')->where('code', '=', 'wechat_appid')->value('value'); //商户号,也就是商户申请的商户号 $mch_id = Db::name('config_data')->where('code', '=', 'mch_id')->value('value'); //这里的是商户号的秘钥,要区分商户号和小程序ID的秘钥 $miyao = Db::name('config_data')->where('code', '=', 'pay_secret')->value('value'); //生成订单号 if (!$out_num) { //未传入订单号,直接生成 $out_num = ikzOutNum(); } $res_url = 'https://' . request()->host() . $path; //处理传入的信息 $info = json_encode($info); /*支付XML数组*/ //小程序数据组装 $pay_arr = array( //以下是必填项 'appid' => $appid,//公众号appid 'mch_id' => $mch_id,//商户号 'attach' => $info,//这里存放数据库信息 'nonce_str' => get_rand_str(), //随机字符串表 'body' => $title, //商品描述 'out_trade_no' => $out_num, //订单号 'total_fee' => $money * 100, //付款金额 单位分 'spbill_create_ip' => gethostbyname(input('server.SERVER_NAME')),//终端ip,服务器所允许的ip,微信商户后台可以配置 'notify_url' => $res_url, //通知地址 这个是你的异步通知地址,微信商户后台进行设置的 'trade_type' => 'JSAPI', 'openid' => $openid, //openid ); $sing_str = get_sign($miyao, $pay_arr); //将拼接好的签名写入数组 $pay_sign = array('sign' => $sing_str); $pay_xml_array = array_merge($pay_arr, $pay_sign); $pay_xml_array = arrayToXml($pay_xml_array); $send_url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; $responseXml = curl_post_ssl($send_url, $pay_xml_array); $responseObj = (array)simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA); // echo json_encode($responseObj);die(); //判断数据是否返回成功 if (!empty($responseObj) && $responseObj['return_code'] == 'SUCCESS' && $responseObj['result_code'] == 'SUCCESS') { //数据返回成功 //小程序端支付 $prepay_id = $responseObj['prepay_id']; $jsApiParameters_array = array( "appId" => $appid, "timeStamp" => (string)time(), "nonceStr" => get_rand_str(), "package" => "prepay_id=" . $prepay_id, "signType" => "MD5" ); $pay_sing_str = get_sign($miyao, $jsApiParameters_array); $pay_sign_ary = array('paySign' => $pay_sing_str); $pay_xml_array_pay = array_merge($jsApiParameters_array, $pay_sign_ary); //将支付开启状态进行封装 $pay_status = array('status' => 'success'); $pay_xml_array_pay = array_merge($pay_status, $pay_xml_array_pay); $res_info['status'] = 'success'; $res_info['pay'] = $pay_xml_array_pay; $res_info['out_num'] = $out_num; $res_info['total'] = $responseObj; $res_info['app'] = $pay_arr; $res_info['res_url'] = $res_url; } else { //数据返回失败 $res_info['status'] = 'pay_error'; $res_info['out_num'] = $out_num; //记录错误信息 recordOrderError($out_num, json_encode($responseObj), '2'); } return $res_info;
//请求数据的方法 function curl_post_ssl($url, $vars, $cert = false, $cert_path = '', $second = 30, $aHeader = array()) { $ch = curl_init(); //超时时间 curl_setopt($ch, CURLOPT_TIMEOUT, $second); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //这里设置代理,如果有的话 curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); if ($cert) { //第一种方法,cert 与 key 分别属于两个.pem文件 //默认格式为PEM,可以注释 curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM'); curl_setopt($ch, CURLOPT_SSLCERT, $cert_path['cert']); //默认格式为PEM,可以注释 curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM'); curl_setopt($ch, CURLOPT_SSLKEY, $cert_path['key']); } if (count($aHeader) >= 1) { curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader); } curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $vars); $data = curl_exec($ch); if ($data) { curl_close($ch); return $data; } else { $error = curl_errno($ch); curl_close($ch); return false; } }
//生成随机数 function get_rand_str() { $str = '1234567890abcdefghijklmnopqrstuvwxyz'; $t1 = ''; for ($i = 0; $i < 30; $i++) { $j = rand(0, 35); $t1 .= $str[$j]; } return $t1; }
//设置请求参数的方法 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; }
//错误信息统一记录函数 function recordOrderError($out_num, $content, $type) { $error = Db::name('error_order'); $error_data['error_out_num'] = $out_num; $error_data['error_type'] = $type; $error_data['error_info'] = $content; $error->insertGetId($error_data); }
/* *生成签名的方法 *@param $my 商户应用密钥 */ function get_sign($my, $hongbao_arr) { ksort($hongbao_arr); //按照ASCII 码 从 小 到 大 排 序 $unSignParaString = formatQueryParaMap($hongbao_arr, false); return sign($unSignParaString, $my); }
/** * 生成订单号 * @param $length * @return string * @throws ClientException */ function ikzOutNum($info = '') { return $info . date('YmdHis') . rand(1000000, 9999999); }