本文作者原版,编写人程序小白:Mason.Hu
我们这里就不说怎么申请微信APP支付
有不会的童鞋可以参照这么前辈写的文档,不过好像不用我们申请,APP端干的事情。 —— [ 微信APP支付接入 ]
本编辑器支持 Markdown Extra , 扩展了很多好用的功能。具体请参考[Github][2].
好了那我们就开始我们的APP开发斩棘之旅吧!
文档还是要看的,先大致了解一下流程嘛! 微信开发文档
流程图(简单了解下就行了哈)
由于微信官方没有提供APP的demo,那我们就引用公众号的demo吧! 微信公众号demo
我们先填写需要的配置信息,此处略过,参数如何填写官方写的很详细。 WxPay.Config.php
然后我们就开始写微信APP支付接口吧
<?php
//引入配置文件
require_once(DIR_WS_MODULES . 'app/weixin/lib/WxPay.Api.php');
require_once(DIR_WS_MODULES . 'app/weixin/lib/WxPay.Data.php');
require_once(DIR_WS_MODULES . 'app/weixin/lib/WxPay.Config.php');
switch($_GET['request_aciton']){
case 'check_weChatPay':
/*拼接签名字符串
*return $buff将拼接好的字符串返回*/
function ToUrlParams($data)
{
$buff = "";
foreach ($data as $k => $v)
{
if($k != "sign" && $v != "" && !is_array($v)){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
/*这是为了测试方便讲价格设置为0.01*/
$price = 0.01;
$orders_id = $_POST['orders_id'] ? $_POST['orders_id'] : '';
/*此处的zen_get_orders_number是自己写的获取订单号的函数*/
$out_trade_no = zen_get_orders_number($orders_id);
/*为什么乘以100呢 因为1代表1分钱*/
$total_fee = (string)(100 * $price);
/*body就是商品的描述信息 此处我定义了一个常量 也可以用字符串直接写*/
$body = APP_WE_CHAT_PAY;
/*此处设置的是一个回调地址*/
$notify_url = 'http://回调地址的路径';
/*调用统一下单接口*/
$input = new WxPayUnifiedOrder();
$appid = '此处填写appid';
/*设置APPID*/
$input->SetAppid($appid);
/*设置描述信息*/
$input->SetBody($body);
/*设置交易订单号*/
$input->SetOut_trade_no($out_trade_on);
/*设置金额*/
$input->SetTotal_fee($total_fee);
$input->SetTime_start(date("YmdHis"));
$input->SetTime_expire(date("YmdHis", time() + 600));
/*设置回调地址*/
$input->SetNotify_url($notify_url);
/*设置交易类型*/
$input->SetTrade_type("APP");
/*设置产品金额*/
$input->SetProduct_id($total_fee);
/*调用微信统一下单的方法*/
$unifiedOrderResult = WxPayApi::unifiedOrder($input);
$value = array(
"appid" => $unifiedOrderResult['appid'],
"partnerid" =>$unifiedOrderResult['mch_id'],
"prepayid" => $unifiedOrderResult['prepay_id'],
"noncestr" => $unifiedOrderResult['nonce_str'],
"timestamp" => time(),
'package' => 'Sign=WXPay'
);
/*参数名ASCII码从小到大排序(字典序)*/
ksort($value);
/*调用上面写的方法*/
$str = ToUrlParams($value);
/*拼接字符串*/
$str = $str . "&key=".WxPayConfig::KEY;
/*md5加密*/
$str = md5($str);
/*转化成大写*/
$str = strtoupper($str);
//将下单获取的信息重新签名 demo没有这一步,为出错的原因
$value['sign'] = $str;
$value["orderid"] = $out_trade_no;
$value["price"] = $total_fee;
$value["url"] = $notify_url;
/*successReturn是我封装的一个函数就是返回json_encode处理的数据*/
successReturn($value);
break;
default:
failReturn(400); /*失败返回的json*/
break;
}
我们需要介绍几个参数,防止入坑!
微信规定得参数 | 要写成这样 |
---|---|
appId | appid |
partnerId | partnerid |
prepayId | prepayid |
nonceStr | noncestr |
timeStamp | timestamp(切记是时间戳【10位】) |
package | package |
按照上面的代码就可以调起微信了,至于怎麽调起就是APP端的操作了。或许有些人会比较好奇,为什么只签名了一次,其实在调用微信的WxPayApi::unifiedOrder已经签名了并且将数据转化成xml数组发送给服务器了。
至于他的$inputObj->SetSign();怎么来的呢?我们可以参考WxPay.Data.php这个文件,他在这个文件定义这个SetSign方法,然后她又调用了这个类文件里面的MakeSign()方法,从而实现了第一次签名!
SetSign()方法
MakeSign()方法
其实代码还可以再精简一点,后面我们也可以用SetSign()方法进行二次签名。
下面我们就开始写回调了:(这里我直接引用的它的example文件中的notify.php文件)
<?php
ini_set('date.timezone','Asia/Shanghai'); /*设置时区*/
/*导入所需要的配置文件*/
require_once "../lib/WxPay.Api.php";
require_once '../lib/WxPay.Notify.php';
require_once 'log.php';
/*我这个引用的是服务器的配置信息,主要是做数据库链接*/
require_once("../../../../configure.php");
/*初始化日志,这个就是我们引用的log.php,实例化其中的这个类,目的就是为了监测微信给我们返回的数据。*/
$logHandler= new CLogFileHandler("../logs/".date('Y-m-d').'.log');
$log = Log::Init($logHandler, 15);
/*初始化数据库*/
function connect($zf_host, $zf_user, $zf_password, $zf_database) {
$link = @mysql_connect($zf_host, $zf_user, $zf_password, true);
@mysql_select_db($zf_database, $link);
@mysql_query("SET NAMES '" . DB_CHARSET . "'", $link);
return $link;
}
/*连接数据库*/
$link = connect(DB_SERVER,DB_SERVER_USERNAME,DB_SERVER_PASSWORD,DB_DATABASE);
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];/*我们用来接收服务器返回给我们的数据*/
$order = $_GET; /*获取订单信息*/
/*simplexml_load_strin()读取返回的xml数据,然后返回一个对象我们通过对象提取里面的参数*/
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement',LIBXML_NOCDATA);
$out_trade_no = $postObj->out_trade_no;/*获取微信给我们返回的订单号*/
$result_code = $postObj->result_code;/*获取状态码*/
/*下面我们根据返回的状态就开始处理业务逻辑*/
if($result_code){
//如果订单号不为空
if($out_trade_no){
/*根据订单号查询订单是否存在*/
$orders_number = @mysql_query("select orders_id from orders where orders_number = '$out_trade_no'");
/*如果订单号存在,我们就更改订单状态*/
if($orders_number){
$row = @mysql_fetch_array($orders_number);
$orders_id = $row['orders_id'];
@mysql_query("update orders set orders_status = 2,payment_method='微信支付',payment_module_code='weChatPay' where orders_id = '$orders_id'");
@mysql_query("insert into orders_status_history set orders_id = '$orders_id',orders_status_id=2,date_added='".date('Y-m-d H:i:s')."'");
successReturn(200);/*200 代表成功*/
}
}
}else{
failReturn(400); /*失败返回的状态*/
}
class PayNotifyCallBack extends WxPayNotify
{
//查询订单
public function Queryorder($transaction_id)
{
$input = new WxPayOrderQuery();
$input->SetTransaction_id($transaction_id);
$result = WxPayApi::orderQuery($input);
Log::DEBUG("query:" . json_encode($result));
if(array_key_exists("return_code", $result)
&& array_key_exists("result_code", $result)
&& $result["return_code"] == "SUCCESS"
&& $result["result_code"] == "SUCCESS")
{
return true;
}
return false;
}
//重写回调处理函数
public function NotifyProcess($data, &$msg)
{
Log::DEBUG("call back:" . json_encode($data));
$notfiyOutput = array();
if(!array_key_exists("transaction_id", $data)){
$msg = "输入参数不正确";
return false;
}
//查询订单,判断订单真实性
if(!$this->Queryorder($data["transaction_id"])){
$msg = "订单查询失败";
return false;
}
return true;
}
}
/*获取的当前时间*/
$date = date("Y-m-d H:i:s");
/*调试错误用的上面有写到*/
Log::DEBUG('支付回调测试:' . $date . '订单编号:' .$orders_number . '订单id' . $orders_id);
$notify = new PayNotifyCallBack();
$notify->Handle(false);
虽然微信支付很坑,但是还是不可缺少,微信、支付宝用户毕竟很大的市场,该吐槽吐槽,该用的时候还是要用的!