/** * 发起支付 */ public function pay($user_id, $order_id) { // 查看用户信息 $user_info = $this -> user_info($user_id); // 查看订单信息 $order_info = $this -> order_info($order_id); // 基本信息 $money = $order_info['order_amount'] * 100; $openid = $user_info['mp_unionid']; // 用户openid $order_code = $order_id; // 订单号 $nonce_str = self::getNonceStr(); // 随机字符串 $notify_url = "https://new.zhyin.net/index.php/mobile/pay/zhifu"; // 发送数据 $post_data = [ 'appid' => "", 'mch_id' => "", 'nonce_str' => $nonce_str, 'body' => '智慧印', 'out_trade_no' => $order_code, 'total_fee' => $money, 'spbill_create_ip' => $_SERVER['REMOTE_ADDR'], 'trade_type' => 'JSAPI', 'openid' => $openid, 'notify_url' => $notify_url ]; // 生成签名 $post_data['sign'] = $this->MakeSign($post_data, ""); // 组合XML数据 $xmlData = $this->MakeXml($post_data); // 发送请求 $this->we_chat_url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; $result = $this->curl_post($this->we_chat_url,$xmlData,true); // 解析xml数据 $payment = $this->FromXml($result); // 是否请求成功 if($payment['return_code'] != 'SUCCESS'){ $this->jsonError($payment['return_msg']); } if ($payment['result_code'] == 'SUCCESS'){ $payment['timestamp'] = time(); // 创建统一订单信息 $sign_data = [ 'appId'=>$payment['appid'], 'nonceStr'=>$payment['nonce_str'], 'package'=>'prepay_id=' . $payment['prepay_id'], 'signType'=>'MD5', 'timeStamp'=>'' . $payment['timestamp'] . '', ]; $sign_data['paySign'] = $this->MakeSign($sign_data , ""); return $sign_data; } else { return ['支付失败']; } }
/** * 产生随机字符串,不长于32位 * @param int $length * @return string */ protected static function getNonceStr($length = 32) { $chars = "abcdefghijklmnopqrstuvwxyz0123456789"; $str =""; for ( $i = 0; $i < $length; $i++ ) { $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1); } return $str; } /** * 生成签名 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值 * @param $sign * @param string $keys * @return string */ protected function MakeSign($sign, $keys = '') { ksort($sign); // 数组排序 $str = ''; foreach($sign as $key=>$val){ if($val != ''){ $str .= $key . "=" . $val . "&"; } } $str .= "key=" . $keys; $sign = strtoupper(md5($str)); return $sign; } /** * 生成XML数据 * @param $data * @return string */ protected function MakeXml($data) { $xmlData = "<xml>"; foreach($data as $key=>$val){ $xmlData.="<".$key.">".$val."</".$key.">"; } $xmlData.= "</xml>"; return $xmlData; } /** * POST请求数据 * @param $url * @param $xmlData * @param bool $useCert * @return mixed */ public function curl_post($url, $xmlData, $useCert = false) { $header[] = "Content-type: text/xml"; // POST发送数据 $ch = curl_init(); // 初始化CURL会话 curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); if($useCert == true){ //设置证书 //使用证书:cert 与 key 分别属于两个.pem文件 //证书文件请放入服务器的非web目录下 $sslCertPath = getcwd() . "/wx_cert/apiclient_cert.pem"; $sslKeyPath = getcwd() . "/wx_cert/apiclient_key.pem"; curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLCERT, $sslCertPath); curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLKEY, $sslKeyPath); } curl_setopt($ch, CURLOPT_HTTPHEADER, $header); curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlData); $result = curl_exec($ch); // 获取结果 curl_close($ch);// 关闭会话 return $result; } /** * 将xml转为array * @param $xml * @return mixed */ protected function FromXml($xml) { if(!$xml){ $this->jsonReturn(0,'','XML解析错误!'); } libxml_disable_entity_loader(true); $values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $values; }
回调地址
public function zhifu() { $postXml = file_get_contents('php://input'); libxml_disable_entity_loader(true); $data = json_decode(json_encode(simplexml_load_string($postXml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); $order_id = $data['out_trade_no']; // 订单单号 // 查看有没有这个订单 $order_info_where['order_id'] = $order_id; $order_info_where['order_state'] = 10; $order_info = Db::name('order') -> where($order_info_where) -> find(); // 有这个订单则执行操作 if ($order_info) { $update['order_state'] = '20'; $update['payment_time'] = time(); if (Db::name('order') -> where($order_info_where) -> update($update)) { // 减每个商品的库存 $order_common = Db::name('order_goods') -> where('order_id', $order_id) -> select(); foreach($order_common as $v) { $goods = Db::name('goods') -> where('goods_id', $v['goods_id']) -> field('goods_storage, goods_salenum, goods_id') -> find(); $update_goods['goods_storage'] = $goods['goods_storage'] - $v['goods_num']; $update_goods['goods_salenum'] = $goods['goods_salenum'] + $v['goods_num']; Db::name('goods') -> where('goods_id', $v['goods_id']) -> update($update_goods); } $str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'; } else { $str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>'; } } return $str; }