jsapi支付实现过程比较简单。
开发前必备:
1,已申请公众平台账号,并且开通微信支付认证功能。
2,获取appid
3, 已申请商户平台,需要拿到商户号。
//公众号 appid
private $appid = EVERY_APPID;
//商户号
private $mch_id = '151****';
//支付回调
private $notify_url = '配置自己服务器调用域名/notify_url';
/**
* 立即支付
*/
public function immediatel_pay()
{
$openid = input('openid');//调用接口传递
if(empty($openid)){
return json(
['code'=>1000,'msg'=>'openid不能为空']
);
}
//生成订单号
$order_no = $this->create_order_on();
//支付金额 单位 元
$pay_money = 0.01;
$pay_result = $this->wx_jsapi($order_no,'定金支付成功',$openid,$pay_money);
//入库
try {
//录入数据库信息
} catch (\Exception $e) {
return json(
['code'=>1000,'msg'=>'下单失败,请重新下单']
);
}
}
/**
* 生成订单号
*/
private function create_order_on()
{
$order_id_main = date('YmdHis') . rand(10000000,99999999);
$order_id_len = strlen($order_id_main);
$order_id_sum = 0;
for($i=0; $i<$order_id_len; $i++){
$order_id_sum += (int)(substr($order_id_main,$i,1));
}
$osn = $order_id_main . str_pad((100 - $order_id_sum % 100) % 100,2,'0',STR_PAD_LEFT);
return $osn;
}
private function wx_jsapi($order_no,$body,$openid,$total_fee)
{
// echo '333';
// exit;
$request_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//接口链接
//签名数据
$sign_data = [
'appid' => $this->appid, //公众号appid
'mch_id' => $this->mch_id, //商户号
'nonce_str' => $this->createNoncestr(),
'body' => $body,
'out_trade_no' => $order_no, //商户订单号
'total_fee' => $total_fee*100, //标价金额 分
'notify_url' => $this->notify_url,
'trade_type' => 'JSAPI',
'openid' => $openid //授权获取的openid
];
$sign_data['sign'] = makeSign($sign_data);
$request_param = ArrToXml($sign_data);
$result_xml = $this->https_request($request_url,$request_param);
$result_arr = XmlToArr($result_xml);
//获取预支付交易会话标识
if($result_arr['return_code'] == 'SUCCESS' && $result_arr['result_code'] == 'SUCCESS'){
$timeStamp = time();
//返回前端 $arr
$arr = array(
"appId" => $this->appid,
"timeStamp" => "$timeStamp", //这里是字符串的时间戳,不是int,所以需加引号
"nonceStr" => $this->createNoncestr(),
"package" => "prepay_id=" . $result_arr['prepay_id'],
"signType" => 'MD5',
);
$arr['paySign'] = makeSign($arr);
}else{
}
return $arr;
}
/**
* 作用:产生随机字符串,不长于32位
*/
private function createNoncestr( $length = 32 )
{
$chars = "abcdefghijklmnopqrstuvwxyz0123456789";
$str ="";
for ( $i = 0; $i < $length; $i++ ) {
$str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);
}
return $str;
}
/**
* 模拟 http 请求
* @param String $url 请求网址
* @param Array $data 数据
*/
private function https_request($url, $data = null){
// curl 初始化
$curl = curl_init();
// curl 设置
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
// 判断 $data get or post
if ( !empty($data) ) {
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
// 执行
$res = curl_exec($curl);
curl_close($curl);
return $res;
}
数组转xml
if(!is_array($arr) || count($arr) == 0) return '';
$xml = "<xml>";
foreach ($arr as $key=>$val)
{
if (is_numeric($val)){
$xml.="<".$key.">".$val."</".$key.">";
}else{
$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
}
}
$xml.="</xml>";
xml转数组
libxml_disable_entity_loader(true);
$arr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
生成签名
/**
* 生成签名
* @return 签名,
*/
function makeSign($data)
{
unset($data['sign']);
foreach ($data as $k => $v) {
$Parameters[$k] = $v;
}
//签名步骤一:按字典序排序参数
ksort($Parameters);
$String = formatBizQueryParaMap($Parameters, false);
//签名步骤二:在string后加入KEY
$String = $String . "&key=" . WX_KEY;
//签名步骤三:MD5加密
$String = md5($String);
//签名步骤四:所有字符转为大写
$result_ = strtoupper($String);
return $result_;
}
异步调用
//异步通知
public function notify_url(){
//接收数据
$input_xml = file_get_contents("php://input");
try {
$input_arr = XmlToArr($input_xml);
if(!isset($input_arr['sign'])){
\think\Log::write('WxJsapi---'.var_export('签名未找到',true). 'debug');
exit;
}
//验证签名
$sign_2 = makeSign($input_arr);
if($input_arr['sign'] != $sign_2){
\think\Log::write('WxJsapi---'.var_export('签名错误',true). 'debug');
exit;
}
//修改订单状态
$where = ['order_no'=>$input_arr['out_trade_no'],'status'=>1];
db('bargain_money_order')->where($where)->find();
} catch ( \Exception $e) {
\think\Log::write('WxJsapi---异步通知-------notify_url-- 捕获异常---'.var_export($e->getMessage(),true). 'debug');
}
}
进行了分拆,可以组合使用。如有疑问,欢迎留言沟通。