<?php
if(!defined('DEDEINC')) exit('Request Error!');
/**
 *易宝接口类
 */
class yeepay
{
  var $dsql;
  
  # 业务类型
	# 支付请求，固定值"Buy" 
  var $p0_Cmd = 'Buy';
  
  #	送货地址
	# 为"1": 需要用户将送货地址留在易宝支付系统;为"0": 不需要，默认为 "0".
	var $p9_SAF = "0";
	
  # 网关地址不能随便更改
	var $reqURL_onLine = "https://www.yeepay.com/app-merchant-proxy/node";
	//$reqURL_onLine = "http://tech.yeepay.com:8080/robot/debug.action";
		
  /**
   * 构造函数
   *
   * @access  public
   * @param
   *
   * @return void
   */
  function yeepay()
  {
  	global $dsql;
		$this->dsql = $dsql;
  }

  function __construct()
  {
    $this->yeepay();
  }

  /**
   * 生成支付代码
   * @param   array   $order      订单信息
   * @param   array   $payment    支付方式信息
   */
  function GetCode($order, $payment)
  {
  	global $cfg_basehost;
	
		#	商家设置用户购买商品的支付信息.
		##易宝支付平台统一使用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'];	
		
		#	商户扩展信息
		##商户可以任意填写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 = '<form target="_blank" method="post" action="'.$this->reqURL_onLine.'">
							<input type="hidden" value="'.$this->p0_Cmd.'" name="p0_Cmd">
							<input type="hidden" value="'.$payment['yp_account'].'" name="p1_MerId">
							<input type="hidden" value="'.$p2_Order.'" name="p2_Order">
							<input type="hidden" value="'.$p3_Amt.'" name="p3_Amt">
							<input type="hidden" value="'.$p4_Cur.'" name="p4_Cur">
							<input type="hidden" value="'.$p5_Pid.'" name="p5_Pid">
							<input type="hidden" value="'.$p6_Pcat.'" name="p6_Pcat">
							<input type="hidden" value="'.$p7_Pdesc.'" name="p7_Pdesc">
							<input type="hidden" value="'.$p8_Url.'" name="p8_Url">
							<input type="hidden" value="'.$this->p9_SAF.'" name="p9_SAF">
							<input type="hidden" value="'.$pa_MP.'" name="pa_MP">
							<input type="hidden" value="'.$pd_FrpId.'" name="pd_FrpId">
							<input type="hidden" value="'.$pr_NeedResponse.'" name="pr_NeedResponse"	>
							<input type="hidden" value="'.$hmac.'" name="hmac">
							<input type="submit" value="立即使用YeePay易宝支付"></form>';

    /* 清空购物车 */
		require_once DEDEINC.'/shopcar.class.php';
  	$cart 	= new MemberShops();
    $cart->clearItem();
		$cart->MakeOrders();
    return $button;
  }

  /**
   * 响应操作
   */
  function respond()
  {
   
    /* 引入配置文件 */
    require_once DEDEDATA.'/payment/'.$_REQUEST['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)) {
					$ordertype="goods";
				}elseif(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'];
					
				}else{	
					return $msg = "支付失败，您的订单号有问题!";
				}
	
	
				#	需要比较返回的金额与商家数据库中订单的金额是否相等，只有相等的情况下才认为是交易成功.
				#	并且需要对返回的处理进行事务控制，进行记录的排它性处理，防止对同一条交易重复发货的情况发生.      	  	
				if($r9_BType=="1" || $r9_BType=="3"){
					if($ordertype=="goods"){ 
		    	  if($this->success_db($r6_Order))  return $msg = "支付成功!<br> <a href='/'>返回主页</a> <a href='/member'>会员中心</a>";
		     		else  return $msg = "支付失败!<br> <a href='/'>返回主页</a> <a href='/member'>会员中心</a>";
		     	}elseif($ordertype=="member") {
		      	if($this->success_mem($r6_Order,$pname,$product,$pid))  return $msg = "支付成功!<br> <a href='/'>返回主页</a> <a href='/member'>会员中心</a>";
		     		else  return $msg = "支付失败!<br> <a href='/'>返回主页</a> <a href='/member'>会员中心</a>";
		     	}
				}elseif($r9_BType=="2"){
					#如果需要应答机制则必须回写流,以success开头,大小写不敏感.
					echo "success";
					if($ordertype=="goods"){ 
		    	  if($this->success_db($r6_Order))  return $msg = "支付成功!<br> <a href='/'>返回主页</a> <a href='/member'>会员中心</a>";
		     		else  return $msg = "支付失败!<br> <a href='/'>返回主页</a> <a href='/member'>会员中心</a>";
		     	}elseif($ordertype=="member") {
		      	if($this->success_mem($r6_Order,$pname,$product,$pid))  return $msg = "支付成功!<br> <a href='/'>返回主页</a> <a href='/member'>会员中心</a>";
		     		else  return $msg = "支付失败!<br> <a href='/'>返回主页</a> <a href='/member'>会员中心</a>";
		     	}
				}
			}
			
		}else{
			$this->log_result ("verify_failed");
			return 	$msg = "交易信息被篡!<br> <a href='/'>返回主页</a> ";
		}
  }
  
	
	#签名函数生成签名串
	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'){
			if(!function_exists('iconv')){
				exit('Not install iconv lib!');
			}else{
				$key = iconv("GB2312","UTF-8//IGNORE",$key);
				$data = iconv("GB2312","UTF-8//IGNORE",$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($buyid)
	{
		require_once DEDEINC.'/memberlogin.class.php';
  	$cfg_ml = new MemberLogin();
		$cfg_ml->PutLoginInfo($cfg_ml->M_ID);
		//获取订单信息，检查订单的有效性
		$row = $this->dsql->GetOne("Select state From #@__shops_orders where oid='$buyid' ");
		if($row['state'] > 0)
		{
			return true;
		}	
		$sql = "UPDATE `#@__shops_orders` SET `state`='1' WHERE `oid`='$buyid' AND `userid`='".$cfg_ml->M_ID."';";
		if($this->dsql->ExecuteNoneQuery($sql))
		{
			return true;
		}else{
			return false;
		}	
		return false;
	}
	
	 /*处理点卡，会员升级*/
  function success_mem($order_sn,$pname,$product,$pid){
  	require_once DEDEINC.'/memberlogin.class.php';
  	$cfg_ml = new MemberLogin();
		$cfg_ml->PutLoginInfo($cfg_ml->M_ID);
    
    //更新交易状态为已付款
		$sql = "UPDATE `#@__member_operation` SET `sta`='1' WHERE `buyid`='$order_sn' AND `mid`='".$cfg_ml->M_ID."'";
		$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`='".$cfg_ml->M_ID."'";
				$oldinf="直接充值了".$nrow['num']."金币到帐号！";
			}else{
				$cardid = $row['cardid'];
				$sql1=" Update #@__moneycard_record set uid='".$cfg_ml->M_ID."',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->dsql->Close();
		    $this->log_result("verify_success,订单号:".$order_sn); //将验证结果存入文件
			  return true;
			}else{
				$this->dsql->Close();
				$this->log_result ("verify_failed,订单号:".$order_sn);//将验证结果存入文件
			  return false;
			}
	  /* 改变会员订单状态_支付成功 */
		}elseif($product=="member"){
			$row = $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='".$cfg_ml->M_ID."'");
			if($rs['uptime']!=0 && $rs['exptime']!=0 ) {
				$nowtime = time();
  			$mhasDay = $rs['exptime'] - ceil(($nowtime - $rs['uptime'])/3600/24) + 1;
  			$mhasDay=($mhasDay>0)? $mhasDay : 0;
			}
			$sql1 = "Update #@__member set rank='$rank',exptime='$exptime',uptime='".time()."' where mid='".$cfg_ml->M_ID."'";
			//更新交易状态为已关闭
			$sql2=" Update #@__member_operation set sta='2',oldinfo='会员升级成功!' where buyid='$order_sn' ";
			if($this->dsql->ExecuteNoneQuery($sql1) && $this->dsql->ExecuteNoneQuery($sql2)){
		    $this->dsql->Close();
		    $this->log_result("verify_success,订单号:".$order_sn); //将验证结果存入文件
			  return true;
			}else{
				$this->dsql->Close();
				$this->log_result ("verify_failed,订单号:".$order_sn);//将验证结果存入文件
			  return false;
			}
		}	
  }
	
  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);
	}
	
}
?>