这个支付类是根据官方的文档修改而来!主要实现生成JS API 、Native的package签名包和Native响应的XML格式数据。注释都标上了各方法的用意。由于package包签名,略复杂,这个要自己多花时间去对应去看和log出文件来一一对比!当然只要你用上教程的类,设置好对应的参数就可以正确的生成package参数等
if (isset($argc) && $argc >= 1 && $argv[0] == __FILE__) {
//初始化pay的必要信息
$pay = new WechatPay(array(
WechatPay::APPID => 'wx99dabzpiuq83985b8',
WechatPay::APPSERCER => 'ac12e7e4abaer63hkoa0cc36a9663fa',
WechatPay::PARTNERKEY => 'bae4sfa3562rsfaq23s2045',
WechatPay::PARTNERID => '1268969802',
WechatPay::PAYSIGNKEY => '9Fqsxb3PK4IVOCEc4yCquy5zecS9LeeMjF2Nn4B4YKoOxPwaQdFwMezKT8oNlBYaWcuT',
WechatPay::SIGNTYPE => 'sha1',
));
//设置package 必要的参数 jsapi native都通用
$pay->setParams(WechatPay::BANK_TYPE, "WX");
$pay->setParams(WechatPay::BODY, "test");
$pay->setParams(WechatPay::PARTNER, $pay->partnerid);
$pay->setParams(WechatPay::OUT_TRADE_NO, commonUtil::createNoncestr());
$pay->setParams(WechatPay::TOTAL_FEE, "1");
$pay->setParams(WechatPay::FEE_TYPE, "1");
$pay->setParams(WechatPay::TIMESTAMP, time());
$pay->setParams(WechatPay::NOTIFY_URL, "http://www.demo.com/notify");
$pay->setParams(WechatPay::SPBILL_CREATE_IP, "127.0.0.1");
$pay->setParams(WechatPay::INPUT_CHARSET, "UTF-8");
//JSAPI的签名json
print_r($pay->createJsApiPackage());
//生成native XML
print_r($pay->createNativePackage());
//生成native URL
print_r($pay->createNativeUrl("9701"));
}
JS API生成的package签名包参数:
{
"appId":"wx9998ff5f4dede5b7",
"package":"bank_type=WX&body=test&fee_type=1&input_charset=UTF-8¬ify_url=http%3A%2F%2Fwww.demo.com%2Fnotify&out_trade_no=Vf5qsSwtu0hc2loH&partner=wx9998ff5f4dede5b7&spbill_create_ip=127.0.0.1×tamp=1409295711&total_fee=1&sign=FEE0167BD0D89A88BF6850590EA889B6",
"timeStamp":1409295711,
"nonceStr":"Vf5qsSwtu0hc2loH",
"paySign":"f816264c750923863c370a1739640244b0c2d39c",
"signType":"sha1"
}
Native 响应的XML格式:
Native的URL链接:
weixin://wxpay/bizpayurl?appid=wx9998ff5f4dede5b7&noncestr=VY7cVA6mtVrc1BVq&productid=9701&sign=43508b65b50e1d7e1089be66d55a709469155d73×tamp=1409296323
无论哪一种方式,我们都要通过setParams来设置必要初始化参数和商品价格和状态等!
WechatPay class:
class WechatPay {
const
BANK_TYPE = 'bank_type',
BODY = 'body',
PARTNER = 'partner',
OUT_TRADE_NO = 'out_trade_no',
TIMESTAMP = 'timestamp',
TOTAL_FEE = 'total_fee',
FEE_TYPE = 'fee_type',
NOTIFY_URL = 'notify_url',
SPBILL_CREATE_IP = 'spbill_create_ip',
INPUT_CHARSET = 'input_charset',
APPID = 'appid',
APPSERCER = 'appsercer',
PAYSIGNKEY = 'appkey',
PARTNERID = 'partnerid',
PARTNERKEY = 'partnerkey',
SIGNTYPE = 'signtype';
public
$params = array(), $partnerid = '';
static protected
$_instance;
protected
$_appid, $_appkey, $_signtype, $_partnerkey, $_appsercer;
static public function getInstance(array $options = array()) {
if (empty(self::$_instance)) {
self::$_instance = new self ($options);
}
return self::$_instance;
}
public function __construct(array $options = array()){
$this->_appid = $options[self::APPID];
$this->_appkey = $options[self::PAYSIGNKEY];
$this->_signtype = $options[self::SIGNTYPE];
$this->_partnerkey = $options[self::PARTNERKEY];
$this->_appsercer = $options[self::APPSERCER];
$this->partnerid = $options[self::APPID];
}
public function setParams($param, $paramValue) {
$this->params[CommonUtil::trimString($param)] = CommonUtil::trimString($paramValue);
}
public function getParams($param) {
return $this->params[$param];
}
protected function createNoncestr( $length = 16 ) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$str ="";
for ( $i = 0; $i < $length; $i++ ) {
$str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);
}
return $str;
}
public function checkParams(){
//必要的9个参与签名的参数
if($this->params[self::BANK_TYPE] == null || $this->params[self::BODY] == null || $this->params[self::PARTNER] == null ||
$this->params[self::OUT_TRADE_NO] == null || $this->params[self::TOTAL_FEE] == null || $this->params[self::FEE_TYPE] == null ||
$this->params[self::NOTIFY_URL] == null || $this->params[self::SPBILL_CREATE_IP] == null || $this->params[self::INPUT_CHARSET] == null
) {
return false;
}
return true;
}
/*
* 生成package包
* @params 初始化类时用setParams方法定义必要的9个参数
* 排序后格式化url query形式 再md5SignUtil类签名,再给合URL
*/
protected function getPackageSign(){
try {
if (null == $this->_partnerkey || "" == $this->_partnerkey ) {
throw new Exception("密钥不能为空!" . "
");
}
$commonUtil = new CommonUtil();
ksort($this->params);
$unSignParaString = $commonUtil->formatUrlQuery($this->params, false);
$paraString = $commonUtil->formatUrlQuery($this->params, true);
$md5SignUtil = new MD5SignUtil();
return $paraString . "&sign=" . $md5SignUtil->sign($unSignParaString,commonUtil::trimString($this->_partnerkey));
} catch (Exception $e) {
echo ($e->getMessage());
}
}
/*
* 生成签名方法
* @params appid appkey package timestamp noncestr 等参数而native事例代码中加上retcode reterrmsg两个参数
*/
public function getPaySign($signObj){
foreach ($signObj as $k => $v){
$signParams[strtolower($k)] = $v;
}
try {
if ($this->_appkey == "") {
throw new Exception("APPKEY为空!" . "
");
}
$signParams["appkey"] = $this->_appkey;
ksort($signParams, SORT_STRING);
$commonUtil = new CommonUtil();
$signString = $commonUtil->formatPayUrlQuery($signParams, false);
return sha1($signString);
} catch (Exception $e) {
echo ($e->getMessage());
}
}
//JS API 签名 其中nonceStr是作为订单号 灌穿整个支付流程
public function createJsApiPackage(){
try {
if($this->checkParams() == false) {
throw new Exception("生成package参数缺失!" . "
");
}
$payObj["appId"] = $this->_appid;
$payObj["package"] = $this->getPackageSign();
$payObj["timeStamp"] = $this->getParams(self::TIMESTAMP);
$payObj["nonceStr"] = $this->getParams(self::OUT_TRADE_NO);
$payObj["paySign"] = $this->getPaySign($payObj);
$payObj["signType"] = $this->_signtype;
return json_encode($payObj);
} catch (Exception $e) {
die($e->getMessage());
}
}
/*
* 构建发货状态数组 主要三个参数openid transid orderid
*/
public function createDeliverPost(Array $params) {
$deliver = array();
$deliver['appid'] = $this->_appid;
$deliver['openid'] = $params['openid'];
$deliver['transid'] = $params['transid'];
$deliver['out_trade_no'] = $params['out_trade_no'];
$deliver['deliver_timestamp'] = current_time('timestamp');
$deliver['deliver_status'] = 1;
$deliver['deliver_msg'] = 'OK';
$deliver['app_signature'] = $this->getPaySign($deliver);
$deliver['sign_method'] = 'sha1';
return $deliver;
}
/*
* 生成扫描或者点击原生URL后,响应的XML格式
* @params $retcode $reterrmsg 定义该商品的状态
*/
public function createNativePackage($retcode = 0, $reterrmsg = "ok") {
try {
if ($this->checkParams() == false && $retcode == 0) { //如果是正常的返回, 检查财付通的参数
throw new Exception("生成package参数缺失!" . "
");
}
$nativeObj["AppId"] = $this->_appid;
$nativeObj["Package"] = $this->getPackageSign();
$nativeObj["TimeStamp"] = $this->getParams(self::TIMESTAMP);
$nativeObj["NonceStr"] = $this->getParams(self::OUT_TRADE_NO);
$nativeObj["RetCode"] = $retcode;
$nativeObj["RetErrMsg"] = $reterrmsg;
$nativeObj["AppSignature"] = $this->getPaySign($nativeObj);
$nativeObj["SignMethod"] = $this->_signtype;
$commonUtil = new CommonUtil();
$xml = $commonUtil->arrayToXml($nativeObj);
exit($xml);
}catch (Exception $e) {
echo ($e->getMessage());
}
}
/*
* 生成原生URL 以订单号为参数 这是灌穿整个支付流程
*/
public function createNativeUrl($productid) {
$commonUtil = new CommonUtil();
$nativeObj["appid"] = $this->_appid;
$nativeObj["productid"] = urlencode($productid);
$nativeObj["timestamp"] = time();
$nativeObj["nonceStr"] = commonUtil::createNoncestr();
$nativeObj["sign"] = $this->getPaySign($nativeObj);
$nativeString = $commonUtil->formatPayUrlQuery($nativeObj, false);
return "weixin://wxpay/bizpayurl?".$nativeString;
}
/*
* 取IP地址
*/
public function getIp(){
switch(true) {
case !empty($_SERVER["HTTP_CLIENT_IP"]):
$ip = $_SERVER["HTTP_CLIENT_IP"];
break;
case !empty($_SERVER["HTTP_X_FORWARDED_FOR"]):
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
break;
case !empty($_SERVER["REMOTE_ADDR"]):
$ip = $_SERVER["REMOTE_ADDR"];
break;
default:
$ip = "127.0.0.1";
}
return $ip;
}
}
class MD5SignUtil {
public function sign($content, $key) {
try {
if (null == $key) {
throw new Exception("财付通签名key不能为空!" . "
");
}
if (null == $content) {
throw new Exception("财付通签名内容不能为空" . "
");
}
$signStr = $content . "&key=" . $key;
return strtoupper(md5($signStr));
} catch (Exception $e) {
echo ($e->getMessage());
}
}
public static function verifySignature($content, $sign, $md5Key) {
$signStr = $content . "&key=" . $md5Key;
$calculateSign = strtolower(md5($signStr));
$tenpaySign = strtolower($sign);
return $calculateSign == $tenpaySign;
}
}
class CommonUtil {
public function genAllUrl($toURL, $paras) {
$allUrl = null;
if (null == $toURL) {
die("toURL is null");
}
if (strripos($toURL,"?") =="") {
$allUrl = $toURL . "?" . $paras;
} else {
$allUrl = $toURL . "&" . $paras;
}
return $allUrl;
}
//订单号,可根据实际自定义
static public function createOrderNo() {
$nonce = CommonUtil::createNoncestr(4);
return strtoupper(date('ymds').substr(microtime(),2,4).$nonce);
}
//随机字符串
static public function createNoncestr( $length = 16 ) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$str ="";
for ( $i = 0; $i < $length; $i++ ) {
$str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);
}
return $str;
}
public function splitParaStr($src, $token) {
$resMap = array();
$items = explode($token,$src);
foreach ($items as $item){
$paraAndValue = explode("=",$item);
if ($paraAndValue != "") {
$resMap[$paraAndValue[0]] = $paraAndValue[1];
}
}
return $resMap;
}
static function trimString($value) {
$ret = null;
if (null != $value) {
$ret = $value;
if (strlen($ret) == 0) {
$ret = null;
}
}
return $ret;
}
public function formatUrlQuery($paraMap, $urlencode) {
$buff = "";
ksort($paraMap, SORT_STRING);
foreach ($paraMap as $k => $v) {
if (null != $v && "null" != $v && "sign" != $k) {
if($urlencode) {
$v = urlencode($v);
}
$buff .= $k . "=" . $v . "&";
}
}
$reqPar = '';
if (strlen($buff) > 0) {
$reqPar = substr($buff, 0, strlen($buff)-1);
}
return $reqPar;
}
public function formatPayUrlQuery($paraMap, $urlencode) {
$buff = "";
ksort($paraMap, SORT_STRING);
foreach ($paraMap as $k => $v) {
if($urlencode){
$v = urlencode($v);
}
$buff .= strtolower($k) . "=" . $v . "&";
}
$reqPar = '';
if (strlen($buff) > 0) {
$reqPar = substr($buff, 0, strlen($buff)-1);
}
return $reqPar;
}
/*
* 输出一级数组的xml格式
*/
public function arrayToXml($arr) {
$xml = "
foreach ($arr as $key=>$val) {
if ($key == 'TimeStamp' || $key == 'RetCode') {
$xml.="<".$key.">".$val."".$key.">";
} else
$xml.="<".$key.">".$key.">";
}
$xml .= "
return $xml;
}
}