dsql = $dsql;
}
function __construct()
{
$this->yeepay();
}
/**
* 设定接口会送地址
*
* 例如: $this->SetReturnUrl($cfg_basehost."/tuangou/control/index.php?ac=pay&orderid=".$p2_Order)
*
* @param string $returnurl 会送地址
* @return void
*/
function SetReturnUrl($returnurl='')
{
if (!empty($returnurl))
{
$this->return_url = $returnurl;
}
}
/**
* 生成支付代码
* @param array $order 订单信息
* @param array $payment 支付方式信息
*/
function GetCode($order, $payment)
{
global $cfg_basehost,$cfg_cmspath;
//对于二级目录的处理
if(!empty($cfg_cmspath)) $cfg_basehost = $cfg_basehost.'/'.$cfg_cmspath;
# 商家设置用户购买商品的支付信息.
##易宝支付平台统一使用GBK/GB2312编码方式,参数如用到中文,请注意转码
# 商户订单号,选填.
##若不为"",提交的订单号必须在自身账户交易中唯一;为""时,易宝支付会自动生成随机的商户订单号.
$p2_Order = trim($order['out_trade_no']);
# 支付金额,必填.
##单位:元,精确到分.
$p3_Amt = $order['price'];
# 交易币种,固定值"CNY".
$p4_Cur = "CNY";
# 商品名称
##用于支付时显示在易宝支付网关左侧的订单产品信息.
$p5_Pid = trim($order['out_trade_no']);
# 商品种类
$p6_Pcat = 'cart';
# 商品描述
$p7_Pdesc = '';
# 商户接收支付成功数据的地址,支付成功后易宝支付会向该地址发送两次成功通知.
//$p8_Url = $cfg_basehost."/plus/carbuyaction.php?dopost=return&code=".$payment['code'];
$p8_Url = $cfg_basehost.$this->return_url.'&code='.$payment['code'];
# 商户扩展信息
##商户可以任意填写1K 的字符串,支付成功时将原样返回.
$pa_MP = 'member';
# 应答机制
##为"1": 需要应答机制;为"0": 不需要应答机制.
$pr_NeedResponse = 1;
# 银行编码
##默认为"",到易宝支付网关.若不需显示易宝支付的页面,直接跳转到各银行、神州行支付、骏网一卡通等支付页面,该字段可依照附录:银行列表设置参数值.
$pd_FrpId = '';
#调用签名函数生成签名串
$hmac = $this->getReqHmacString($payment['yp_account'],$payment['yp_key'],$p2_Order,$p3_Amt,$p4_Cur,$p5_Pid,$p6_Pcat,$p7_Pdesc,$p8_Url,$pa_MP,$pd_FrpId,$pr_NeedResponse);
$button = '
';
/* 清空购物车 */
require_once DEDEINC.'/shopcar.class.php';
$cart = new MemberShops();
$cart->clearItem();
$cart->MakeOrders();
return $button;
}
/**
* 响应操作
*/
function respond()
{
/* 引入配置文件 */
$code = preg_replace( "#[^0-9a-z-]#i", "", $_REQUEST['code'] );
require_once DEDEDATA.'/payment/'.$code.'.php';
$p1_MerId = trim($payment['yp_account']);
$merchantKey = trim($payment['yp_key']);
# 解析返回参数.
$return = $this->getCallBackValue($r0_Cmd, $r1_Code, $r2_TrxId, $r3_Amt, $r4_Cur, $r5_Pid, $r6_Order, $r7_Uid, $r8_MP, $r9_BType, $hmac);
# 判断返回签名是否正确(True/False)
$bRet = $this->CheckHmac($p1_MerId,$merchantKey,$r0_Cmd,$r1_Code,$r2_TrxId,$r3_Amt,$r4_Cur,$r5_Pid,$r6_Order,$r7_Uid,$r8_MP,$r9_BType,$hmac);
# 校验码正确.
if($bRet)
{
if($r1_Code=="1")
{
/*判断订单类型*/
if(preg_match ("/S-P[0-9]+RN[0-9]/",$r6_Order))
{
//获取用户mid
$row = $this->dsql->GetOne("SELECT * FROM #@__shops_orders WHERE oid = '{$r6_Order}'");
$this->mid = $row['userid'];
$ordertype="goods";
} else if (preg_match ("/M[0-9]+T[0-9]+RN[0-9]/",$r6_Order)){
$row = $this->dsql->GetOne("SELECT * FROM #@__member_operation WHERE buyid = '{$r6_Order}'");
//获取订单信息,检查订单的有效性
if(!is_array($row)||$row['sta']==2) return $msg = "您的订单已经处理,请不要重复提交!";
$ordertype = "member";
$product = $row['product'];
$pname= $row['pname'];
$pid=$row['pid'];
$this->mid = $row['mid'];
} else {
return $msg = "支付失败,您的订单号有问题!";
}
# 需要比较返回的金额与商家数据库中订单的金额是否相等,只有相等的情况下才认为是交易成功.
# 并且需要对返回的处理进行事务控制,进行记录的排它性处理,防止对同一条交易重复发货的情况发生.
if($r9_BType == "1" || $r9_BType == "3"){
if($ordertype == "goods"){
if($this->success_db($r6_Order)) return $msg = "支付成功!
返回主页 会员中心";
else return $msg = "支付失败!
返回主页 会员中心";
} else if ($ordertype=="member") {
$oldinf = $this->success_mem($r6_Order,$pname,$product,$pid);
return $msg = "".$oldinf."
返回主页 会员中心";
}
} else if ( $r9_BType == "2" ){
#如果需要应答机制则必须回写流,以success开头,大小写不敏感.
echo "success";
if($ordertype=="goods"){
if($this->success_db($r6_Order)) return $msg = "支付成功!
返回主页 会员中心";
else return $msg = "支付失败!
返回主页 会员中心";
} else if ($ordertype=="member") {
if($this->success_mem($r6_Order,$pname,$product,$pid)) return $msg = "支付成功!
返回主页 会员中心";
else return $msg = "支付失败!
返回主页 会员中心";
}
}
}
} else {
$this->log_result ("verify_failed");
return $msg = "交易信息被篡!
返回主页 ";
}
}
#签名函数生成签名串
function getReqHmacString($p1_MerId,$merchantKey,$p2_Order,$p3_Amt,$p4_Cur,$p5_Pid,$p6_Pcat,$p7_Pdesc,$p8_Url,$pa_MP,$pd_FrpId,$pr_NeedResponse)
{
#进行签名处理,一定按照文档中标明的签名顺序进行
$sbOld = "";
#加入业务类型
$sbOld = $sbOld.$this->p0_Cmd;
#加入商户编号
$sbOld = $sbOld.$p1_MerId;
#加入商户订单号
$sbOld = $sbOld.$p2_Order;
#加入支付金额
$sbOld = $sbOld.$p3_Amt;
#加入交易币种
$sbOld = $sbOld.$p4_Cur;
#加入商品名称
$sbOld = $sbOld.$p5_Pid;
#加入商品分类
$sbOld = $sbOld.$p6_Pcat;
#加入商品描述
$sbOld = $sbOld.$p7_Pdesc;
#加入商户接收支付成功数据的地址
$sbOld = $sbOld.$p8_Url;
#加入送货地址标识
$sbOld = $sbOld.$this->p9_SAF;
#加入商户扩展信息
$sbOld = $sbOld.$pa_MP;
#加入银行编码
$sbOld = $sbOld.$pd_FrpId;
#加入是否需要应答机制
$sbOld = $sbOld.$pr_NeedResponse;
return $this->HmacMd5($sbOld,$merchantKey);
}
# 取得返回串中的所有参数
function getCallBackValue(&$r0_Cmd,&$r1_Code,&$r2_TrxId,&$r3_Amt,&$r4_Cur,&$r5_Pid,&$r6_Order,&$r7_Uid,&$r8_MP,&$r9_BType,&$hmac)
{
$r0_Cmd = $_REQUEST['r0_Cmd'];
$r1_Code = $_REQUEST['r1_Code'];
$r2_TrxId = $_REQUEST['r2_TrxId'];
$r3_Amt = $_REQUEST['r3_Amt'];
$r4_Cur = $_REQUEST['r4_Cur'];
$r5_Pid = $_REQUEST['r5_Pid'];
$r6_Order = $_REQUEST['r6_Order'];
$r7_Uid = $_REQUEST['r7_Uid'];
$r8_MP = $_REQUEST['r8_MP'];
$r9_BType = $_REQUEST['r9_BType'];
$hmac = $_REQUEST['hmac'];
return NULL;
}
function CheckHmac($p1_MerId,$merchantKey,$r0_Cmd,$r1_Code,$r2_TrxId,$r3_Amt,$r4_Cur,$r5_Pid,$r6_Order,$r7_Uid,$r8_MP,$r9_BType,$hmac)
{
if($hmac == $this->getCallbackHmacString($p1_MerId,$merchantKey,$r0_Cmd,$r1_Code,$r2_TrxId,$r3_Amt,$r4_Cur,$r5_Pid,$r6_Order,$r7_Uid,$r8_MP,$r9_BType))
return TRUE;
else
return FALSE;
}
function getCallbackHmacString($p1_MerId,$merchantKey,$r0_Cmd,$r1_Code,$r2_TrxId,$r3_Amt,$r4_Cur,$r5_Pid,$r6_Order,$r7_Uid,$r8_MP,$r9_BType)
{
#取得加密前的字符串
$sbOld = "";
#加入商家ID
$sbOld = $sbOld.$p1_MerId;
#加入消息类型
$sbOld = $sbOld.$r0_Cmd;
#加入业务返回码
$sbOld = $sbOld.$r1_Code;
#加入交易ID
$sbOld = $sbOld.$r2_TrxId;
#加入交易金额
$sbOld = $sbOld.$r3_Amt;
#加入货币单位
$sbOld = $sbOld.$r4_Cur;
#加入产品Id
$sbOld = $sbOld.$r5_Pid;
#加入订单ID
$sbOld = $sbOld.$r6_Order;
#加入用户ID
$sbOld = $sbOld.$r7_Uid;
#加入商家扩展信息
$sbOld = $sbOld.$r8_MP;
#加入交易结果返回类型
$sbOld = $sbOld.$r9_BType;
return $this->HmacMd5($sbOld,$merchantKey,'gbk');
}
function HmacMd5($data,$key,$lang='utf-8')
{
//RFC 2104 HMAC implementation for php.
//Creates an md5 HMAC.
//Eliminates the need to install mhash to compute a HMAC
//Hacked by Lance Rushing(NOTE: Hacked means written)
//需要配置环境支持iconv,否则中文参数不能正常处理
if($GLOBALS['cfg_soft_lang'] != 'utf-8' || $lang!='utf-8')
{
$key = gb2utf8($key);
$data = gb2utf8($data);
}
$b = 64; //byte length for md5
if (strlen($key) > $b) {
$key = pack("H*",md5($key));
}
$key = str_pad($key, $b, chr(0x00));
$ipad = str_pad('', $b, chr(0x36));
$opad = str_pad('', $b, chr(0x5c));
$k_ipad = $key ^ $ipad ;
$k_opad = $key ^ $opad;
return md5($k_opad.pack("H*",md5($k_ipad.$data)));
}
/*处理物品交易*/
function success_db($order_sn)
{
//获取订单信息,检查订单的有效性
$row = $this->dsql->GetOne("SELECT state FROM #@__shops_orders WHERE oid='$order_sn' ");
if($row['state'] > 0)
{
return TRUE;
}
/* 改变订单状态_支付成功 */
$sql = "UPDATE `#@__shops_orders` SET `state`='1' WHERE `oid`='$order_sn' AND `userid`='".$this->mid."'";
if($this->dsql->ExecuteNoneQuery($sql))
{
$this->log_result("verify_success,订单号:".$order_sn); //将验证结果存入文件
return TRUE;
} else {
$this->log_result ("verify_failed,订单号:".$order_sn);//将验证结果存入文件
return FALSE;
}
}
/*处理点卡,会员升级*/
function success_mem($order_sn,$pname,$product,$pid)
{
//更新交易状态为已付款
$sql = "UPDATE `#@__member_operation` SET `sta`='1' WHERE `buyid`='$order_sn' AND `mid`='".$this->mid."'";
$this->dsql->ExecuteNoneQuery($sql);
/* 改变点卡订单状态_支付成功 */
if($product=="card")
{
$row = $this->dsql->GetOne("SELECT cardid FROM #@__moneycard_record WHERE ctid='$pid' AND isexp='0' ");;
//如果找不到某种类型的卡,直接为用户增加金币
if(!is_array($row))
{
$nrow = $this->dsql->GetOne("SELECT num FROM #@__moneycard_type WHERE pname = '{$pname}'");
$dnum = $nrow['num'];
$sql1 = "UPDATE `#@__member` SET `money`=money+'{$nrow['num']}' WHERE `mid`='".$this->mid."'";
$oldinf ="已经充值了".$nrow['num']."金币到您的帐号";
} else {
$cardid = $row['cardid'];
$sql1=" UPDATE #@__moneycard_record SET uid='".$this->mid."',isexp='1',utime='".time()."' WHERE cardid='$cardid' ";
$oldinf='您的充值密码是:'.$cardid.'';
}
//更新交易状态为已关闭
$sql2=" UPDATE #@__member_operation SET sta=2,oldinfo='$oldinf' WHERE buyid='$order_sn'";
if($this->dsql->ExecuteNoneQuery($sql1) && $this->dsql->ExecuteNoneQuery($sql2))
{
$this->log_result("verify_success,订单号:".$order_sn); //将验证结果存入文件
return $oldinf;
} else {
$this->log_result ("verify_failed,订单号:".$order_sn);//将验证结果存入文件
return "支付失败";
}
/* 改变会员订单状态_支付成功 */
} else if ( $product=="member" ){
$row = $this->dsql->GetOne("SELECT rank,exptime FROM #@__member_type WHERE aid='$pid' ");
$rank = $row['rank'];
$exptime = $row['exptime'];
/*计算原来升级剩余的天数*/
$rs = $this->dsql->GetOne("SELECT uptime,exptime FROM #@__member WHERE mid='".$this->mid."'");
if($rs['uptime']!=0 && $rs['exptime']!=0 )
{
$nowtime = time();
$mhasDay = $rs['exptime'] - ceil(($nowtime - $rs['uptime'])/3600/24) + 1;
$mhasDay=($mhasDay>0)? $mhasDay : 0;
}
//获取会员默认级别的金币和积分数
$memrank = $this->dsql->GetOne("SELECT money,scores FROM #@__arcrank WHERE rank='$rank'");
//更新会员信息
$sql1 = " UPDATE #@__member SET rank='$rank',money=money+'{$memrank['money']}',
scores=scores+'{$memrank['scores']}',exptime='$exptime'+'$mhasDay',uptime='".time()."'
WHERE mid='".$this->mid."'";
//更新交易状态为已关闭
$sql2=" UPDATE #@__member_operation SET sta='2',oldinfo='会员升级成功!' WHERE buyid='$order_sn' ";
if($this->dsql->ExecuteNoneQuery($sql1) && $this->dsql->ExecuteNoneQuery($sql2))
{
$this->log_result("verify_success,订单号:".$order_sn); //将验证结果存入文件
return "会员升级成功";
} else {
$this->log_result ("verify_failed,订单号:".$order_sn);//将验证结果存入文件
return "会员升级失败";
}
}
}
function log_result($word) {
global $cfg_cmspath;
$fp = fopen(dirname(__FILE__)."/../../data/payment/log.txt","a");
flock($fp, LOCK_EX) ;
fwrite($fp,$word.",执行日期:".strftime("%Y-%m-%d %H:%I:%S",time())."\r\n");
flock($fp, LOCK_UN);
fclose($fp);
}
}//End API