前端页面
//验证是不是微信内置浏览器
function is_weixn(){
var ua = navigator.userAgent.toLowerCase();
if(ua.match(/MicroMessenger/i) == "micromessenger"){
return true;
} else {
return false;
}
}
PHP
case '3': //微信内置浏览器JSAPI支付
$sHtml = '<form id="orderSubmit" name="orderSubmit" action="'.U('Wechat/wxpayJsApi').'" method="post">';
$sHtml .= '<input type="hidden" name="out_trade_no" value="'.$order['order_sn'].'" />';
$sHtml .= '<input type="hidden" name="body" value="萄萄汇商城 - '.$goods_name.'" />';
$sHtml .= '<input type="hidden" name="total_fee" value="'.$order['payable_amount'].'" />';
$sHtml .= '<input type="submit" value="Submit" style="display:none;" /></form>';
$sHtml .= '<script>document.forms["orderSubmit"].submit();</script>';
echo $sHtml;
break;
DEOM
<?php
namespace Mobile\Controller;
use Think\Controller;
class WechatController extends Controller{
//$stime = microtime(true);
//$etime = microtime(true); echo ($etime - $stime);
//需先设置好微信支付受权目录和网页受权域名,扫码支付模式一需设置支付回调URL,模式二不须要设置
const TOKEN = 'StupidLi'; //token令牌
//const ORIGINAL_ID = 'gh_63e349ac0af5'; //微信公众号原始ID
const APP_ID = 'wx8d7d0d6d81dc5056'; //微信公众号应用ID
const APP_SECRET = 'cc41f16e6620443dcb7a4f6e85efbbca'; //微信公众号应用密钥
//const ENCODING_AES_KEY = 'S1X0CAP7JlNInE6NKyglXdZWt2rrh0g1oIIpOOil3rH'; //消息加解密密钥
const MCH_ID = '1420243602'; //微信支付商户号
const MCH_KEY = '0MrxTO6bhOikziaGnAMgr1xec9bIFRxP'; //微信支付商户密钥
const RETURN_URL = 'http://m.tthwine.com/Wechat/wxpayReturn.html'; //支付结果同步通知地址
const NOTIFY_URL = 'http://m.tthwine.com/Wechat/wxpayNotify.html'; //支付结果异步通知地址
/**
* TODO:设置商户证书路径
* 证书路径,注意应该填写绝对路径(仅退款、撤销订单时须要,可登陆商户平台下载,
* API证书下载地址:https://pay.weixin.qq.com/index.php/account/api_cert,下载以前须要安装商户操做证书)
*/
const SSLCERT_PATH = './ThinkPHP/Library/Vendor/Wechat/cert/apiclient_cert.pem';
const SSLKEY_PATH = './ThinkPHP/Library/Vendor/Wechat/cert/apiclient_key.pem';
/**
* TODO:这里设置CURL代理机器,只有须要代理的时候才设置,不须要代理,请设置为0.0.0.0和0
* 本例程经过curl使用HTTP POST方法,此处可修改代理服务器,
* 默认CURL_PROXY_HOST=0.0.0.0和CURL_PROXY_PORT=0,此时不开启代理(若有须要才设置)
*/
const CURL_PROXY_HOST = '0.0.0.0'; //"10.152.18.220"
const CURL_PROXY_PORT = 0; //8080
private $access_token = ''; //公共基础开发的access_token
private $access_token_a = ''; //用户受权凭证,即用code换取的access_token,
private $curl_timeout = 30; //curl超时
public function _initialize(){
header("Content-type: text/html; charset=utf-8");
vendor("Wechat.WxPayException"); //异常处理类
vendor("Wechat.WxPayFunction"); //基础方法类
}
//微信应用基础开发服务地址
public function index(){
//file_put_contents('./Data/paylog/wechatlog.txt', $_SERVER['REMOTE_ADDR'].' '.$_SERVER['QUERY_STRING']."\r\n", FILE_APPEND);
if(isset($_GET['echostr'])){ //验证token
$checkResult = $this->checkSignature($_GET['signature'], TOKEN, $_GET['timestamp'], $_GET['nonce']);
if($checkResult == true){
echo $_GET['echostr'];
exit;
}
}else{
$this->reponseMsg();
//其余基础开发程序
//libxml_disable_entity_loader(true);
//$values = json_decode(json_encode(simplexml_load_string($res, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
//file_put_contents("./Data/paylog/TEXTQ.txt", "1111333", FILE_APPEND );
}
}
//应用开发验证签名
protected function checkSignature($signature, $token, $timestamp, $nonce){
$tmpArr = array($token, $timestamp, $nonce);
sort($tmpArr, SORT_STRING);
$tmpStr = implode($tmpArr);
$tmpStr = sha1($tmpStr);
if($tmpStr == $signature){
return true;
}else{
return false;
}
}
//回复事件
public function reponseMsg(){
//1.获取到微信推送过来post数据(xml格式)
$postArr = $GLOBALS['HTTP_RAW_POST_DATA'];
//2.处理消息类型,并设置回复类型和内容
$postObj = simplexml_load_string( $postArr );
//判断该数据包是不是订阅的事件推送
if( strtolower( $postObj->MsgType) == 'event'){
//若是是关注 subscribe 事件
if( strtolower($postObj->Event == 'subscribe') ){
//回复用户消息(纯文本格式)
$toUser = $postObj->FromUserName;
$fromUser = $postObj->ToUserName;
$arr = array(
array(
'title'=>'中秋月醇-月饼礼盒套装可预约啦',
'description'=>"中秋月醇-十二星座红酒配月饼礼盒套装能够预约了",
'picUrl'=>'https://mmbiz.qlogo.cn/mmbiz_jpg/gOCpHN587Z330josics98BkbFntIeVHq795A4ibqicANzzicdOico79kqOaHHicdMeFD9CwyKhk1BYTw4sS7icuTg0V1g/0?wx_fmt=jpeg',
'url'=>'https://mp.weixin.qq.com/s?__biz=MzIzMTY5MzI3Ng==&mid=2247483661&idx=1&sn=7e51c19aa3ec2672986c4b35d07e74b1&chksm=e8a10fbedfd686a8cd571951b64abcf2f680e6bdcbfdf4fb764dae22a961d9c91b78e471b5a3#rd',
),
array(
'title'=>'百葡汇--名庄红酒价格搜索中心',
'description'=>"百葡汇--名庄红酒价格搜索中心",
'picUrl'=>'http://www.baipuhui.com/Public/Home/Images/logo.png',
'url'=>'http://www.baipuhui.com/',
),
array(
'title'=>'萄萄汇--红酒商城',
'description'=>"葡葡汇--红酒商城",
'picUrl'=>'http://www.tthwine.com/Public/Home/img/logo.png',
'url'=>'http://m.tthwine.com',
),
);
$template = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<ArticleCount>".count($arr)."</ArticleCount>
<Articles>";
foreach($arr as $k=>$v){
$template .="<item>
<Title><![CDATA[".$v['title']."]]></Title>
<Description><![CDATA[".$v['description']."]]></Description>
<PicUrl><![CDATA[".$v['picUrl']."]]></PicUrl>
<Url><![CDATA[".$v['url']."]]></Url>
</item>";
}
$template .="</Articles>
</xml> ";
echo sprintf($template, $toUser, $fromUser, time(), 'news');
}elseif( strtolower($postObj->Event == 'unsubscribe') ){
//回复用户消息(纯文本格式)
$toUser = $postObj->FromUserName;
$fromUser = $postObj->ToUserName;
$time = time();
$msgType = 'event';
$event = 'unsubscribe';
$content = '欢迎关注咱们的微信公众帐号';
$template = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Event><![CDATA[%s]]></Event>
</xml>";
$info = sprintf($toUser, $fromUser, $time, $msgType, $event, $content, $template);
echo $info;
}
}
//内容的回复多图文的
if( strtolower($postObj->MsgType) == 'text' && strtolower($postObj->Content)=='tw' ){
$toUser = $postObj->FromUserName;
$fromUser = $postObj->ToUserName;
$arr = array(
array(
'title'=>'再见科比,再见青春',
'description'=>"再见科比,再见青春",
'picUrl'=>'http://img1.gtimg.com/sports/pics/hv1/226/138/2052/133466716.jpg',
'url'=>'http://sports.qq.com/a/20160414/040599.htm',
),
array(
'title'=>'百葡汇--红酒搜索中心',
'description'=>"百葡汇--红酒搜索中心",
'picUrl'=>'http://www.baipuhui.com/Public/Home/Images/logo.png',
'url'=>'http://www.baipuhui.com/',
),
array(
'title'=>'淘淘wine',
'description'=>"淘淘wine",
'picUrl'=>'http://www.tthwine.com/Public/Home/img/logo.png',
'url'=>'http://www.tthwine.com/',
),
);
$template = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<ArticleCount>".count($arr)."</ArticleCount>
<Articles>";
foreach($arr as $k=>$v){
$template .="<item>
<Title><![CDATA[".$v['title']."]]></Title>
<Description><![CDATA[".$v['description']."]]></Description>
<PicUrl><![CDATA[".$v['picUrl']."]]></PicUrl>
<Url><![CDATA[".$v['url']."]]></Url>
</item>";
}
$template .="</Articles>
</xml> ";
echo sprintf($template, $toUser, $fromUser, time(), 'news');
//注意:进行多图文发送时,子图文个数不能超过10个
}else{
switch( strtolower($postObj->Content) ){
case 1:
$content = '您输入的数字是1';
break;
case 2:
$content = '您输入的数字是2';
break;
case 3:
$content = '您输入的数字是3';
break;
case 4:
$content = "<a href='http://www.imooc.com'>慕课</a>";
break;
case '英文':
$content = 'imooc is ok';
break;
}
$template = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
//注意模板中的中括号 不能少 也不能多
$fromUser = $postObj->ToUserName;
$toUser = $postObj->FromUserName;
$time = time();
$msgType = 'text';
echo sprintf($template, $toUser, $fromUser, $time, $msgType, $content);
}//if end
// 付款推送
if( strtolower( $postObj->MsgType) == 'event'){
if( strtolower( $postObj->Event) == 'merchant_order'){
$toUser = $postObj->FromUserName;
$fromUser = $postObj->ToUserName;
$time = time();
$msgType = 'event';
$event = 'merchant_order';
$OrderId = $postObj->OrderId;
$OrderStatus = '2';
$ProductId = $postObj->ProductId;
$SkuInfo = $postObj->SkuInfo;
$template = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Event><![CDATA[%s]]></Event>
<OrderId><![CDATA[%s]]></OrderId>
<OrderStatus>%s</OrderStatus>
<ProductId><![CDATA[%s]]></ProductId>
<SkuInfo><![CDATA[%s]]></SkuInfo>
</xml>";
echo sprintf($template, $toUser, $fromUser, $time, $msgType, $event, $OrderId, $OrderStatus, $ProductId, $SkuInfo);
}
}
return $postArr;
}//reponseMsg 括号
//获取AccessToken
public function getWxAccessToken(){
//1.请求url地址
$appid = 'wx8d7d0d6d81dc5056';
$appsecret = 'cc41f16e6620443dcb7a4f6e85efbbca';
if (time()-S('expires_in')<7000) {
$access_token = S('access_token');
//var_dump($access_token);
return $access_token;
}else{
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . $appid . "&secret=" . $appsecret . "";
$data = webCurl($url);
$arr = json_decode($data,true);
S('access_token',$arr['access_token'],7000);
$access_token = S('access_token');
$data = array(
"access_token" => $access_token,
"expires_in"=> time(),
);
S('expires_in',$data['expires_in'],7000);
//var_dump($access_token);
//$_SESSION['access_token_expires_in'] = $data['expires_in'];
return $data['access_token'];
}
}
//自定义菜单栏
public function setmenu()
{
$access_token = $this->getWxAccessToken();
$url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=".$access_token;
$data = array(
'button'=>array(
array(
"name"=>"微信商城",
"sub_button"=>array(
array(
"type"=>"view",
"name"=>"中秋月醇",
"url"=>"http://m.tthwine.com/Goods/index/W_category/376.html"
),
array(
"type"=>"view",
"name"=>"生肖套装",
"url"=>"http://m.tthwine.com/Goods/detail/id/413.html"
),
array(
"type"=>"view",
"name"=>"萄萄汇商城",
"url"=>"http://m.tthwine.com/"
),
array(
"type"=>"view",
"name"=>"特价优惠",
"url"=>"http://m.tthwine.com/Goods/index.html"
),
)
),
array(
"name"=>"名庄报价",
"sub_button"=>array(
array(
"type"=>"view",
"name"=>"价格查询",
"url"=>"http://m.baipuhui.com/"
),
array(
"type"=>"view",
"name"=>"供应商报价",
"url"=>"http://m.baipuhui.com/ProductPrice/indexs.html"
),
array(
"type"=>"view",
"name"=>"全球货源",
"url"=>"http://m.baipuhui.com/BusinessList/index.html"
),
)
),
array(
"name"=>"用户中心",
"sub_button"=>array(
// array(
// "type"=>"view",
// "name"=>"小店订单",
// "url"=>"http://mp.weixin.qq.com/bizmall/mallshelf?id=&t=mall/list&biz=MzIzMTY5MzI3Ng==&shelf_id=2&showwxpaytitle=1#wechat_redirect"
// ),
array(
"type"=>"view",
"name"=>"商城订单",
"url"=>"http://m.tthwine.com/Member/order.html"
),
array(
"type"=>"view",
"name"=>"物流跟踪",
"url"=>"https://m.kuaidi100.com/index.jsp"
),
array(
"type"=>"view",
"name"=>"我的中心",
"url"=>"http://m.tthwine.com/Member/index.html"
),
)
),
),
);
$data = webCurl($url,1,json_encode($data,JSON_UNESCAPED_UNICODE));
}
//登陆获取用户信息
public function login()
{
$appid = 'wx8d7d0d6d81dc5056';
$redirect_uri = "http://m.tthwine.com/index.php/Wechat/weixinreturn";
$redirect_uri = urlencode($redirect_uri);
$url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=".$appid."&redirect_uri=".$redirect_uri."&response_type=code&scope=snsapi_userinfo&state=1&connect_redirect=1#wechat_redirect";
header('Location: ' . $url . '');
}
public function weixinreturn()
{
$appid = 'wx8d7d0d6d81dc5056';
$SECRET = 'cc41f16e6620443dcb7a4f6e85efbbca';
$code = $_GET['code'];
$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" .$appid. "&secret=" .$SECRET. "&code=". $code ."&grant_type=authorization_code";
$data = json_decode(wcurl($url),true);
$_SESSION['access_token'] = $data['access_token'];
$_SESSION['openid'] = $data['openid'];
$url = "https://api.weixin.qq.com/sns/userinfo?access_token=".$_SESSION['access_token']."&openid=".$_SESSION['openid']."&lang=zh_CN";
$user = json_decode(wcurl($url),true);
$this->assign('user',$user);
$this->display();
return $user;
}
//微信小店下单信息
public function order(){
$obj = $this-> gOrderAll($data = array());
foreach ($obj['order_list'] as $key => $value) {
$sql = " SELECT order_id FROM oph_wxshop WHERE order_id = '{$value['order_id']}' ";
$res = M('wxshop')->query($sql);
if ($res[0]['order_id'] == $value['order_id'] ) {
unset($value);
}else{
M('wxshop')->add($value);
}
}
$get['type']= $_GET['type'] ? $_GET['type'] : 0 ;
switch ($get['type']){
case 0:
$where = '';
break;
case 1:
$where = ' AND order_status = 1 ';
break;
case 2:
$where = ' AND order_status = 2 ';
break;
case 3:
$where = ' AND order_status = 3 ';
break;
case 4:
$where = ' AND order_status = 4 ';
break;
default:
break;
}
$orderlist = M('wxshop')->query(" SELECT * FROM oph_wxshop WHERE buyer_openid = '{$_SESSION['openid']}' $where");
$this->assign('orderlist',$orderlist);
$this->assign('get',$get);
$this->display();
}
//微信小店的订单详情
public function orderinfo(){
$oid = $_GET['order_id'] ? $_GET['order_id'] : $this->error("非法访问");
$info = M('wxshop')->query(" SELECT * FROM oph_wxshop WHERE order_id = '{$oid}' ");
$this->assign('info', $info);
$this->display();
}
//获取微信订单信息
public function gOrderAll($data = array()){
$access_token = $this->getWxAccessToken();
$url = "https://api.weixin.qq.com/merchant/order/getbyfilter?access_token=".$access_token;
if(!empty($data)){
$data = json_encode($data);
}
else{
$firstday = strtotime(date("Y-m-01",time()));
$data = array('begintime' => $firstday,'endtime' => strtotime("$firstday +1 month -1 day"));
$data = json_encode($data);
}
$ResData = $this->cUrlRequest($url,$data);
$obj = objarray_to_array(json_decode($ResData));
return $obj;
}
public function cUrlRequest($url,$data = null){
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($data)){
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
//微信订单确认
public function returnInfo(){
if($_GET['oid']){
M()->execute("UPDATE oph_wxshop SET order_status = 4 WHERE order_id = '{$_GET['oid']}'");
}
$orderlist = M('wxshop')->query(" SELECT * FROM oph_wxshop WHERE buyer_openid = '{$_SESSION['openid']}' AND order_status = 4");
$this->assign('orderlist',$orderlist);
$this->display('wechat/order');
}
//微信小店发货
public function sLogisticsList(){
$this->Logistics['Fsearch_code'] = "邮政EMS";
$this->Logistics['002shentong'] = "申通快递";
$this->Logistics['066zhongtong'] = "中通速递";
$this->Logistics['056yuantong'] = "圆通速递";
$this->Logistics['042tiantian'] = "每天快递";
$this->Logistics['003shunfeng'] = "顺丰速运";
$this->Logistics['059Yunda'] = "韵达快运";
$this->Logistics['064zhaijisong'] = "宅急送";
$this->Logistics['020huitong'] = "汇通快运";
$this->Logistics['zj001yixun'] = "易迅快递";
}
//发货设置
public function sOrderDelivery($data = array("need_delivery" => '0')){
$access_token = $this->getWxAccessToken();
$url = "https://api.weixin.qq.com/merchant/order/setdelivery?access_token=".$access_token;
if(!empty($data)){
$data = json_encode($data);
}
else{
$data = array("need_delivery" => '0');
$data = json_encode($data);
}
$ResData = $this->cUrlRequest($url,$data);
print_r( json_decode($ResData) );
}
//发货订单
public function send()
{
$data['need_delivery'] = '1';
$data['order_id'] = '13880016931595576467';
$data['delivery_company'] = '003shunfeng';
$data['delivery_track_no'] = '5185457726';
$data['is_others'] = '0';
$this->sOrderDelivery($data);
}
//获取订单详情
// public function gOrderInfo($order){
// $access_token = $this->getWxAccessToken();
// $url = "https://api.weixin.qq.com/merchant/order/getbyid?access_token=".$access_token;
// $ResData = $this->cUrlRequest($url,'{"order_id": "'.$order.'"}');
// return(objarray_to_array(json_decode($ResData)) );
// }
//模板消息发送
public function sendtpl_msg(){
if (is_weixin() == false) {
echo "<p style='font-size:32px;color:red;text-align:center'>请用微信浏览器打开</p>";
exit;
}
$access_token = $this->getWxAccessToken();
$getOpenid = $this->getOpenid();
//$postArr = $this->reponseMsg();
//$res = $this->gOrderInfo($postArr['OrderId']);
//模板消息
$template=array(
'touser'=>$getOpenid,
'template_id'=>"t2j4tatkUhqCvsTVr290P04rXNWg3WnMWXOHiLW6tSg",
'url'=>"http://m.tthwine.com/index.php/Wechat/login/",
'topcolor'=>"#7B68EE",
'data'=>array(
'first' => array(
'value' => '尊敬的用户,您好,欢迎购买咱们的产品',
'color' => '#FF0000'
),
'keyword1' => array(
'value' => $data['order_no'],
'color' => '#000'
),
'keyword2' => array(
'value' => $data['pay_amount'].元,
'color' => '#000000'
),
'remark' => array(
'value' => '广州欧葡汇祝您节日快乐!',
'color' => '#FF0000'
)
)
);
$json_template=json_encode($template);
$url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=".$access_token;
$res = http_request($url,urldecode($json_template));
}
/**
* 以post方式提交xml到对应的接口url
* @param string $xml 须要post的xml数据
* @param string $url url
* @param bool $useCert 是否须要证书,默认不须要
* @param int $second url执行超时时间,默认30s
* @throws WxPayException
*/
protected static function curlPostXml($xml, $url, $useCert = false, $second = 30){
$ch = curl_init();
curl_setopt($ch, CURLOPT_TIMEOUT, $second); //设置超时
if(self::CURL_PROXY_HOST != "0.0.0.0" && self::CURL_PROXY_PORT != 0){ //若是有配置代理这里就设置代理
curl_setopt($ch, CURLOPT_PROXY, self::CURL_PROXY_HOST);
curl_setopt($ch, CURLOPT_PROXYPORT, self::CURL_PROXY_PORT);
}
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); //严格校验2
curl_setopt($ch, CURLOPT_HEADER, FALSE); //设置header
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); //要求结果为字符串且输出到屏幕上
if($useCert == true){ //设置证书,使用证书:cert 与 key 分别属于两个.pem文件
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLCERT, self::SSLCERT_PATH);
curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLKEY, self::SSLKEY_PATH);
}
curl_setopt($ch, CURLOPT_POST, TRUE); //post提交方式
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
$result = curl_exec($ch); //运行curl
if($result){ //返回结果
curl_close($ch);
return $result;
}else{
$error = curl_errno($ch);
curl_close($ch);
throw new \WxPayException("curl出错,错误码:".$error);
}
}
/**
* 经过跳转获取用户的openid,跳转流程以下:
* 一、设置本身须要调回的url及其其余参数,跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize
* 二、微信服务处理完成以后会跳转回用户redirect_uri地址,此时会带上一些参数,如:code
* 三、经过code请求微信服务器https://api.weixin.qq.com/sns/oauth2/access_token获取openid和access_token用户受权凭证
* @param string $state 自定义参数
* @return 用户的openid
*/
protected function getOpenid($state=''){
$tools = new \WxPayFunction();
if(!isset($_GET['code'])){ //触发微信返回code码
$redirectUrl = urlencode('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'].$_SERVER['QUERY_STRING']);
$urlObj = array(
'appid' => self::APP_ID,
'redirect_uri' => $redirectUrl,
'response_type' => 'code',
'scope' => 'snsapi_base',
'state' => $state.'#wechat_redirect'
);
$bizString = $tools->ToUrlStr($urlObj);
$url = 'https://open.weixin.qq.com/connect/oauth2/authorize?'.$bizString;
header('Location:'.$url); exit();
}else{ //获取code码,以获取openid
$urlObj = array(
'appid' => self::APP_ID,
'secret' => self::APP_SECRET,
'code' => $_GET['code'],
'grant_type' => 'authorization_code'
);
$bizString = $tools->ToUrlStr($urlObj);
$url = 'https://api.weixin.qq.com/sns/oauth2/access_token?'.$bizString;
$ch = curl_init(); //初始化curl
curl_setopt($ch, CURLOPT_TIMEOUT, $this->curl_timeout); //设置超时
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
if(self::CURL_PROXY_HOST != '0.0.0.0' && self::CURL_PROXY_PORT != 0){
curl_setopt($ch,CURLOPT_PROXY, self::CURL_PROXY_HOST);
curl_setopt($ch,CURLOPT_PROXYPORT, self::CURL_PROXY_PORT);
}
$result = curl_exec($ch); //运行curl,结果以json形式返回
curl_close($ch);
$data = json_decode($result, true);
$this->access_token_a = $data['access_token']; //赋值access_token_a属性,此access_token为用户受权凭证,与基础开发的access_token不一样
return $data['openid']; //返回openid
}
}
/**
* 统一下单,unifiedOrder中out_trade_no、body、total_fee、trade_type必填
* appid、mchid、spbill_create_ip、nonce_str不须要填入
* @param WxPayUnifiedOrder $inputObj
* @param int $timeOut
* @throws WxPayException 抛出异常
* @return array 成功时返回结果
*/
protected function unifiedOrder($requestArr, $timeOut = 10){
//检测参数
if(!array_key_exists('out_trade_no', $requestArr)){
throw new \WxPayException("缺乏统一支付接口必填参数out_trade_no!");
}else if(!array_key_exists('body', $requestArr)){
throw new \WxPayException("缺乏统一支付接口必填参数body!");
}else if(!array_key_exists('total_fee', $requestArr)){
throw new \WxPayException("缺乏统一支付接口必填参数total_fee!");
}else if(!array_key_exists('trade_type', $requestArr)){
throw new \WxPayException("缺乏统一支付接口必填参数trade_type!");
}
//关联参数
if($requestArr['trade_type'] == "JSAPI" && !array_key_exists('openid', $requestArr)){
throw new WxPayException("统一支付接口中,缺乏必填参数openid!trade_type为JSAPI时,openid为必填参数!");
}
if($requestArr['trade_type'] == "NATIVE" && !array_key_exists('product_id', $requestArr)){
throw new WxPayException("统一支付接口中,缺乏必填参数product_id!trade_type为JSAPI时,product_id为必填参数!");
}
$tools = new \WxPayFunction();
$url= 'https://api.mch.weixin.qq.com/pay/unifiedorder'; //统一下单API请求地址
$requestArr['appid'] = self::APP_ID; //String(32) 应用ID
$requestArr['mch_id'] = self::MCH_ID; //String(32) 商户ID
$requestArr['nonce_str'] = $tools->createNonceStr(32); //String(32) 随机字符串
$requestArr['spbill_create_ip'] = $_SERVER['REMOTE_ADDR']; //String(16) 终端IP
$requestArr['notify_url'] = self::NOTIFY_URL; //String(256) 异步通知地址
$requestArr['sign'] = $tools->createSign($requestArr, self::MCH_KEY); //String(32) 签名
$requestXml = $tools->arrToXml($requestArr);
$responseXml = self::curlPostXml($requestXml, $url, false, $timeOut);
$responseArr = $tools->xmlToArr($responseXml);
return $responseArr;
}
/**
* 获取jsApi的json参数
* @param string $prepay_id 预支付交易标识
* @return jsApi前端json参数
*/
protected function getJsApiParameters($prepay_id){
$tools = new \WxPayFunction();
$jsApiArr = array(
'appId' => self::APP_ID, //String(16) 应用ID
'timeStamp' => strval(time()), //String(32) 时间戳
'nonceStr' => $tools->createNonceStr(32), //String(32) 随机字符串
'package' => 'prepay_id='.$prepay_id, //String(128) 订单详情扩展字符串
'signType' => 'MD5' //String(32) 签名方式
);
$jsApiArr['paySign'] = $tools->createSign($jsApiArr, self::MCH_KEY); //String(64) 签名
return json_encode($jsApiArr);
}
/**
* 获取共享地址json参数
* @param string $access_token 用户受权凭证
* @return 共享地址前段json参数
*/
protected function getEditAddrParameters($access_token){
$tools = new \WxPayFunction();
$addrSignArr = array(
'appid' => self::APP_ID, //String(16) 应用ID
'url' => 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'], //当前网页URL
'timestamp' => strval(time()), //String(32) 时间戳
'noncestr' => $tools->createNonceStr(32), //String(32) 随机字符串
'accesstoken' => $access_token //String(256) 用户受权凭证
);
ksort($addrSignArr);
$addrSignStr = $tools->toUrlStr($addrSignArr);
$addrSign = sha1($addrSignStr);
$editAddrArr = array(
'appId' => self::APP_ID, //String(16) 应用ID
'scope' => 'jsapi_address', //String(32) 编辑地址权限
'signType' => 'sha1', //String(32) 签名方式
'addrSign' => $addrSign, //String(40) 签名
'timeStamp' => $addrSignArr['timestamp'], //String(32) 时间戳
'nonceStr' => $addrSignArr['noncestr'] //String(32) 随机字符串
);
return json_encode($editAddrArr);
}
//微信支付外部浏览器H5页面MWEB支付接口(微信内测阶段,还未对外开放)
public function wxpayH5Api(){
$requestArr = array(
'body' => $_POST['body'], //String(128) 商品描述
'out_trade_no' => $_POST['out_trade_no'], //String(32) 商户订单号
'total_fee' => intval(floatval($_POST['total_fee'])*100), //Int 订单金额(单位为分)
'trade_type' => 'MWEB' //String(16) 交易类型
);
$responseArr = $this->unifiedOrder($requestArr); //统一下单API
$tools = new \WxPayFunction();
if($responseArr['return_code'] == 'SUCCESS'){ //判断返回是否成功
if(array_key_exists('sign', $responseArr) && $tools->createSign($responseArr, self::MCH_KEY) == $responseArr['sign']){
header('Location:'.$responseArr['mweb_url'].'&redirect_url='.urlencode(self::RETURN_URL)); //跳转启动微信APP支付
}else{
throw new \WxPayException("签名验证失败!");
}
}else{ //$responseArr['return_code'] == 'FAIL'
//记录日志$responseArr;打印出错参数
//file_put_contents('./Data/paylog/wechatlog.txt', $_SERVER['REMOTE_ADDR'].' '.$_SERVER['QUERY_STRING']."\r\n", FILE_APPEND);
throw new \WxPayException("响应失败!");
foreach($responseArr as $key => $val){
echo $key.': '.$val.'<br />';
}
}
}
//微信支付内置浏览器H5页面JSAPI支付接口
public function wxpayJsApi(){
//获取openId需跳转,因此将post参数存入获取openid的自定义参数中
if(!empty($_POST['body']) && !empty($_POST['out_trade_no']) && !empty($_POST['total_fee'])){
$state = json_encode($_POST);
}
//解析获取openid返回的自定义参数,从而获取最初的订单信息
if(!empty($_GET['state'])){
$orderData = json_decode($_GET['state'], true);
}
$openid = $this->getOpenid($state); //获取openid
$requestArr = array(
'body' => $orderData['body'], //String(128) 商品描述
'out_trade_no' => $orderData['out_trade_no'], //String(32) 商户订单号
'total_fee' => intval(floatval($orderData['total_fee'])*100), //Int 订单金额(单位为分)
'trade_type' => 'JSAPI', //String(16) 交易类型
'openid' => $openid //String(128) trade_type=JSAPI时(即公众号支付),此参数必传,此参数为微信用户在商户对应appid下的惟一标识
);
$responseArr = $this->unifiedOrder($requestArr); //统一下单API
if(!array_key_exists('appid', $responseArr) || !array_key_exists('prepay_id', $responseArr) || $responseArr['prepay_id'] == ""){
throw new \WxPayException("参数错误!");
}
//获取调用jsApi的参数(json格式输出)
$jsApiParameters = $this->getJsApiParameters($responseArr['prepay_id']);
//获取共享收货地址的参数(json格式输出)(因为支付场景不适合,暂不使用)
//$editAddrParameters = $this->getEditAddrParameters($this->access_token_a);
//传递给同步通知页面的信息
$returnData = array(
// 'out_trade_no' => $orderData['body'],
'out_trade_no' => $orderData['out_trade_no'],
'total_fee' => $orderData['total_fee'],
'return_url' => self::RETURN_URL
);
$this->assign('jsApiParameters', $jsApiParameters);
//$this->assign('editAddrParameters', $editAddrParameters);
$this->assign('returnData', $returnData);
$this->display('Order/wxpay_js');
}
//微信支付原生支付接口(采用模式二扫码支付)
public function wxpayNativeApi(){
$requestArr = array(
'body' => $_POST['body'], //String(128) 商品描述
'out_trade_no' => $_POST['out_trade_no'], //String(32) 商户订单号
'total_fee' => intval(floatval($_POST['total_fee'])*100), //Int 订单金额(单位为分)
'trade_type' => 'NATIVE', //String(16) 交易类型
'product_id' => $_POST['out_trade_no'] //String(32) 商品标识,商户自定义
);
$responseArr = $this->unifiedOrder($requestArr); //统一下单API
$tools = new \WxPayFunction();
if($responseArr['return_code'] == 'SUCCESS'){ //判断返回是否成功
if(array_key_exists('sign', $responseArr) && $tools->createSign($responseArr, self::MCH_KEY) == $responseArr['sign']){ //验证签名
$returnData = array( //获取订单信息和扫码支付地址
'out_trade_no' => $_POST['out_trade_no'],
'total_fee' => $_POST['total_fee'],
'code_url' => $responseArr['code_url']
);
}else{
throw new \WxPayException("签名验证失败!");
}
}else{ //$responseArr['return_code'] == 'FAIL'
throw new \WxPayException("响应失败!");
foreach($responseArr as $key => $val){
echo $key.': '.$val.'<br />';
}
}
$this->assign('returnData', $returnData);
$this->display('Order/wxpay_native');
}
//微信支付同步通知
public function wxpayReturn(){
$payResult = array(
'order_no' => htmlspecialchars($_GET['out_trade_no']),
'status' => $_GET['status'],
'pay_type' => '微信支付',
'pay_amount' => $_GET['total_fee']
);
if($payResult['status'] == 'success'){ //支付完成
M('order')->where('`order_sn`="'.$payResult['order_no'].'" AND `pay_status`=0')->setField('pay_status', 1);
$crowd = M('order')->alias('o')->where('(o.`is_crowd`<>0 OR o.`is_cab`<>0) AND o.`order_sn`="'.$payResult['order_no'].'"')->join('`oph_order_goods` AS og ON og.`order_id`=o.`id`','left')->join('`oph_crowd` AS c ON (c.`id`=o.`is_crowd` OR c.`id`=o.`is_cab`)','left')->field('og.`goods_id`,og.`number`,og.`box`,o.`id` oid,o.`is_crowd`,o.`is_cab`,c.*')->find();
// var_dump($crowd);exit;
if(!$_COOKIE[$payResult['order_no']]){
setcookie($payResult['order_no'],1);
if ($crowd) {
$upNum['nownum'] = $crowd['nownum'] + $crowd['number'];
$myCrowd = array();
M()->startTrans();
if ($crowd['is_crowd']) {
$res = M('crowd')->where('id='.$crowd['is_crowd'])->setField($upNum);
$myCrowd['cid'] = $crowd['is_crowd'];
}else{
$res = M('crowd')->where('id='.$crowd['is_cab'])->setField($upNum);
$myCrowd['cid'] = $crowd['is_cab'];
}
$myCrowd['myprice'] = $payResult['pay_amount'];
$myCrowd['uid'] = $_SESSION['user']['uid'];
$myCrowd['mobile'] = $_SESSION['user']['mobile'];
$myCrowd['num'] = $crowd['number'];
$order['total'] = $myCrowd['num'];
$myCrowd['create_time'] = time();
$myCrowd['oid'] = $crowd['oid'];
if ($res) {
M('crowd_join')->add($myCrowd);
M()->commit();
}else{
M()->rollback();
}
}
$order['total'] = M('order')->alias('o')->where('o.`order_sn`="'.$payResult['order_no'].'" AND og.`goods_id`<>0')->join('oph_order_goods AS og ON og.`order_id`=o.`id`')->sum('number');
$jiage = $payResult['pay_amount'];
D('member')->upLevel($jiage,$order['total']);
}
$payResult['msg'] = '付款完成!咱们将第一时间安排发货!';
//发送模板消息
$access_token = $this->getWxAccessToken();
$getOpenid = $this->getOpenid();
//模板消息
$template=array(
'touser'=>$getOpenid,
'template_id'=>"t2j4tatkUhqCvsTVr290P04rXNWg3WnMWXOHiLW6tSg",
'url'=>"http://m.tthwine.com/Member/order",
'topcolor'=>"#7B68EE",
'data'=>array(
'first' => array(
'value' => '尊敬的用户,您好,欢迎购买咱们的产品',
'color' => '#FF0000'
),
'keyword1' => array(
'value' => $payResult['pay_amount'].元,
'color' => '#000'
),
'keyword2' => array(
'value' => $payResult['order_no'],
'color' => '#000000'
),
'remark' => array(
'value' => '广州十二星祝您节日快乐!',
'color' => '#FF0000'
)
)
);
$json_template=json_encode($template);
$url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=".$access_token;
http_request($url,urldecode($json_template));
}else if($payResult['status'] == 'failure'){ //支付失败或出错
$payResult['msg'] = '支付失败,请到个人订单从新发起支付!';
}
$this->assign('payResult', $payResult); //print_r($payResult);
$this->display('Order/result');
}
//微信支付异步通知
public function wxpayNotify(){
$notifyXml = $GLOBALS['HTTP_RAW_POST_DATA']; //获取返回的xml数据
$tools = new \WxPayFunction();
$notifyArr = $tools->xmlToArr($notifyXml);
if($notifyArr['return_code'] == 'SUCCESS'){ //判断通知成功
if($notifyArr['result_code'] == 'SUCCESS' && $tools->createSign($notifyArr, self::MCH_KEY) == $notifyArr['sign']){ //支付成功和验证签名
$pay_status = M('order')->where('`order_sn`="'.$notifyArr['out_trade_no'].'"')->getField('pay_status');
if(self::MCH_ID == $notifyArr['mch_id'] && $pay_status != 1){
$data = array(
'pay_type' => 3,
'pay_status' => 1,
'payreal_amount' => floatval($notifyArr['total_fee']/100), //单位为分,换算成元
'pay_sn' => $notifyArr['transaction_id'],
'pay_time' => strtotime($notifyArr['time_end'])
);
$result = M('order')->where('order_sn="'.$notifyArr['out_trade_no'].'"')->save($data);
}
}
//写入日志文件(订单编号,微信交易号,交易状态,交易金额,微信用户openId,付款时间)
file_put_contents('./Data/paylog/wxpaylog.txt', $notifyArr['out_trade_no'].' '.$data['pay_sn'].' '.$notifyArr['result_code'].' '.$data['payreal_amount'].' '.$notifyArr['openid'].' '.$data['pay_time'].' 微信支付'."\r\n", FILE_APPEND);
$responseXml = $tools->arrToXml(array('return_code'=>'SUCCESS', 'return_msg'=>'OK'));
echo $responseXml;
}else{
return false;
}
}
//分享接口
public function sharOne(){
//获取商品id
$shopId = I('get.sid');
$getgm = I('get.gm');
$jsapi_ticket = $this->getJsApiTicket();
$timestamp = time();
$noncestr = $this->getRandCode();
// 注意 URL 必定要动态获取,不能 hardcode.
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
$url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
$signature = "jsapi_ticket=$jsapi_ticket&noncestr=$noncestr×tamp=$timestamp&url=$url";
$signature = sha1( $signature );
if($shopId > 0){
//获取用户微信getOpenid
$getOpenid = $this->getOpenid();
$getOpenid = str_replace('-','',$getOpenid);
//获取上级分享的用户openid
if($upOpenid = I('get.u')) $this->assign('upOpenid',$upOpenid);
$newUrl = $protocol.$_SERVER[HTTP_HOST].'/Wechat/sharOne/u/'.$getOpenid.'/sid/'.$shopId.'.html';
$this->assign('shopId',$shopId);
$this->assign('getOpenid',$getOpenid);
$this->assign('newUrl',$newUrl);
}
//获取地区三级联动
$province = M('region_china')->where('pid=0')->getField('id,region_name');
$showVive = 'sharOne'.$shopId;
$this->assign('getgm',$getgm);
$this->assign('province',$province);
$this->assign('timestamp',$timestamp);
$this->assign('noncestr',$noncestr);
$this->assign('signature',$signature);
$this->assign('sharOnesid',$shopId);
$this->display($showVive);
}
//获取随机码
public function getRandCode(){
$array = 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','d','u','v','w','x','y','z',
'0','1','2','3','4','5','6','7','8','9'
);
$tmpstr = '';
$max = count($array);
for($i =1; $i <= 16; $i++){
$key = rand(0,$max-1);
$tmpstr .= $array[$key];
}
return $tmpstr;
}
public function getJsApiTicket(){
//若是session中保存有效的jsapi_ticket
$access_token = $this->getWxAccessToken();
if($_SESSION['jsapi_ticket_expire_time'] > time()){
$jsapi_ticket = S('jsapi_ticket');
}else{
$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=$access_token&type=jsapi";
$data = webCurl($url);
$res = json_decode($data,true);
$jsapi_ticket = $res['ticket'];
S('jsapi_ticket',$jsapi_ticket,7000);
$_SESSION['jsapi_ticket_expire_time'] = time()+7000;
}
return $jsapi_ticket;
}
}
?>