年初时公司要在官网上添加一个支付功能“银联商务”支付。这个支付系统支持许多的银行在线支付。写在这里希望能帮助一些需要的朋友。

   虽然ecshop的支付方式已经有好多了,但有时也有使用其它没有有支付系统。当然如果能看懂这个添加过程,那么其它的支付功能添加也不会太难。

   与“银联商务”签合同就不说了。签合同后“银联商务”会给我们一个测试帐号与测试地址。ecshop网站添加“银联商务”支付功能_第1张图片   这是测试与调试必须要的。

  还得到商户的控制台(用上面的地址帐号登录)下面的 "ChinaPay安装插件下载" 里找到下载 "NetPayClient php (通用版)安装程序" 。下载后里面有只一个PHP文件是处理整个加密密钥程序,必须要的,虽然代码进行了加密,但高手一看就可以解密出来。

ecshop网站添加“银联商务”支付功能_第2张图片

一般我们可以不用解密出来,直接可以使用。如果没有解密那文件可以放在/includes/modules/  下。不要放在/includes/modules/payment/ 下。

  这个程序要用到PHP的“bcmath”高精度数学函数库,这个库在window里是自带的,但在linux里必须一般要安装才能使用。当然如果PHP已经安装了这个扩展就没有必要再装了。

  linux系统下,给PHP安装扩展方法有很多,这时说下我使用的方法:

       在终端输入命令  yum install php-bcmath  回车后 就可以等待安装完成。

  下面来说下流程:

ecshop网站添加“银联商务”支付功能_第3张图片

   在/includes/modules/payment/   下新建一个支付文件,命名可以自己定义的。如 chinaPay.php  这里就以chinaPay.php为名。

添加以下代码:

//银联商务  支付接囗

if (!defined('IN_ECS'))
{
   die('Hacking attempt');
}
$payment_lang = ROOT_PATH . 'languages/' .$GLOBALS['_CFG']['lang']. '/payment/'.basename(__FILE__);
if (file_exists($payment_lang))
{
   global $_LANG;
   include_once($payment_lang);
}

/* 安装模块的基本信息后台管理中用到的 */
if (isset($set_modules) && $set_modules == TRUE)
{
   $i = isset($modules) ? count($modules) : 0;
   /* 代码 */
   $modules[$i]['code']    = basename(__FILE__, '.php');
   /* 描述对应的语言项 */
   $modules[$i]['desc']    = 'chinaPay_desc';//对应语言文件中的说明内容下标
   /* 是否货到付款 */
   $modules[$i]['is_cod']  = '0';
   /* 是否支持在线支付 */
   $modules[$i]['is_online']  = '1';
   /* 作者 */
   $modules[$i]['author']  = 'XIHUAN';
   /* 网址 */
   $modules[$i]['website'] = 'http://www.ecshop.com';
   /* 版本号 */
   $modules[$i]['version'] = '1.0.0';
   /* 配置信息 表单元素*/
   $modules[$i]['config']  = array(
       array('name' => 'chinaPay_MerId',/*对应语言文件中的下标*/       'type' => 'text',   'value' => ''),//商户号
       array('name' => 'chinaPay_MerPrk', /*对应语言文件中的下标*/     'type' => 'text',   'value' => ''),//商户签名私钥地址
       array('name' => 'chinaPay_PgPubk', /*对应语言文件中的下标*/     'type' => 'text',   'value' => '')//ChinaPay签名私钥地址
   );
   return;
}

include ROOT_PATH.'/includes/modules/netpayclient.php'//如果解密了这个文件可以把代码定到这里就不用这句代码

/**
* 类
*/
class chinaPay{
   function chinaPay()
   {
   }
   function __construct()
   {
       $this->chinaPay();
   }
   //获取指定长度的字符串  不足以0填充
   function str($str,$len,$fill='0')
   {
       if(strlen($str)<$len)
       {
           return str_repeat($fill, $len-strlen($str)).$str;
       }
       return substr($str, 0,$len);
   }
   //金额处理
   function order_amount($amount)
   {
       if(strpos($amount, '.'))
           return $this->str(str_replace('.', '', $amount), 12);
       else return $this->str($amount.'00', 12);
   }
   /**
    * 生成支付代码
    * @param   array   $order      订单信息
    * @param   array   $payment    支付方式信息
    * 这里必须根据要求生成银联商务可用的连接代码
    */
   function get_code($order, $payment)
   {
       //创建签名钥
       if(empty($payment['chinaPay_MerId'])||empty($payment['chinaPay_MerPrk'])||!buildKey($payment['chinaPay_MerPrk']))return '

支付出错!请联系园田居!

';
       $order_no=$this->str($order['order_sn'], 16);//处理定单
       $TransAmt=$this->order_amount($order['order_amount']);//订单交易金额
       $Priv1='chinaPay';
       $CuryId='156';//订单交易币种
       $TransDate=date('Ymd');//订单交易日期
       $TransType='0001';//交易类型
       $msg=$payment['chinaPay_MerId'].$order_no.$TransAmt.$CuryId.$TransDate.$TransType.$Priv1;
       $button='
'.// (这里action的内容为提交交易数据的URL地址)
       ''.// (MerId为ChinaPay统一分配给商户的商户号,15位长度,必填)
       ''. //(商户提交给ChinaPay的交易订单号,16位长度,必填)
       ''. //(订单交易金额,12位长度,左补0, 必填,单位为分)
       ''.// (订单交易币种,3位长度,固定为人民币156, 必填)
       ''.//(订单交易日期,8位长度,必填)
       ''.// (交易类型,4位长度,必填)
       ''.// (支付接入版本号,必填)
       ''.// (后台交易接收URL,长度不要超过80个字节,必填)
       ''.// (页面交易接收URL,长度不要超过80个字节,必填)
       ''.//(支付网关号,可选)
       ''.//(商户私有域,长度不要超过60个字节) 传参数用的
       ''.//(256字节长的ASCII码,为此次交易提交关键数 据的数字签名,必填)
       '
       
';
       return $button;
   }
   /**
    * 响应操作
这里主要处理银联回传的数据  并且要处理付款的形式  是否为付款成功  或付款中  这里的状态很重要
回传的数据  验证最重要的
    */
   function respond()
   {
       /*
       当消费支付交易完成时,ChinaPay会将交易应答信息发送给商户,
       对于页面易接收地址和后台交易接收地址都会收到交易接收数据,
       应答的数据域段包括如下内容:(以页面Form数据为例,注意大小写,
       后台应答数据的发送的域段名和下面的一致)
       
(这里action的内容为提交交易数据的URL地址)
       (MerId为ChinaPay统一分配给商户的商户号,15位长度,必填)
        (商户提交给ChinaPay的交易订单号,16位长度,必填)
        (订单交易日期,8位长度,必填)
        (订单交易金额,12位长度,左补0, 必填,单位为分)
       (订单交易币种,3位长度,固定为人民币156, 必填)
        (交易类型,4位长度,必填)
        (交易状态,4位长度,必填)
        (256字节长的ASCII码,为此次交易提交关键数 据的数字签名,必填)
        (支付网关号,可选)
        (商户私有域,长度不要超过60个字节) 传参数用的
       

       status 表示交易转态,只有"1001"的时候才为交易成功,其他均为失败,因此在验证签名数据为ChinaPay发出的以后,还需要判定交易状态代码为"1001"。
        */
       $sql = "SELECT pay_config FROM " . $GLOBALS['ecs'] ->table('payment') . " WHERE pay_code = 'chinaPay' AND enabled = '1'";
       $pay = $GLOBALS['db']->getRow($sql);//取出内容
       if(empty($pay['pay_config']))return false;//支付配置数据不存在
       $payment = unserialize($pay['pay_config']);
       foreach ($payment as $value)
       {
           if($value['name']=='chinaPay_PgPubk')
           {
               $PgPubk=$value['value'];
               break;
           }

       }
       //创建验证钥
       if(!isset($PgPubk)||!buildKey($PgPubk))return false;
       if (empty($_POST)||!is_array($_POST))return false;//交易失败
       $respond=array('merid','orderno','transdate','amount','currencycode','transtype','status','checkvalue','GateId');
       foreach ($respond as $val)
       {
           if(array_key_exists($val, $_POST));else return false;//交易失败返回数据不合法或缺少
       }
       /* 检查支付的金额是否相符 */
       $order_no=substr($_POST['orderno'], -13);//取出定单号这块可以不去处理SQL注入,后面调用的函数都会判断这个变量的值是否为全数字
       $log_id=get_order_id_by_sn($order_no);//取出支付编号
       //判断是为为充值定单
       if(empty($log_id))$log_id=get_order_id_by_sn($order_no,true);//取出支付编号
       if (!check_money($log_id, (float)substr_replace($_POST['amount'], '.', -2,0)))
       {
           return false;
       }
       //判断交易状态
       if($_POST['status']!='1001')return false;//交易失败
       /* 检查数字签名是否正确 */
       //验证交易应答
       if(!verifyTransResponse($_POST['merid'], $_POST['orderno'], $_POST['amount'], $_POST['currencycode'], $_POST['transdate'], $_POST['transtype'], $_POST['status'], $_POST['checkvalue']))
       return false;//交易失败
           /* 改变订单状态 */
       order_paid($log_id);
      return true;//支付成功
   }
}

?>


以上是整个前端处理核心代码

  然后这个可能建立一个语言文件

ecshop网站添加“银联商务”支付功能_第4张图片

   文件名与支付文件名一样。如果有多个语言可以在/languages/en_us/payment/ ;/languages/zh_cn/payment/ ;/languages/zh_wt/payment/  下都建立一个同样的文件(只要处理好显示的内容为不同的语言就可以)。

添加以下代码:

//银联商务  支付接囗
global $_LANG;
$_LANG['chinaPay'] = '银联商务';
$_LANG['chinaPay_desc'] = '银联商务网站(http://www.chinaums.com/) 是国内先进的网上支付平台。无预付/年费,单笔费率0.6%-0.8%,无流量限制。
立即在线申请';
$_LANG['chinaPay_MerId'] = '商户号';
$_LANG['chinaPay_MerPrk'] = '商户签名私钥地址';
$_LANG['chinaPay_PgPubk'] = 'ChinaPay签名私钥地址';
$_LANG['pay_button'] = '立即使用银联商务支付';

?>

到这里客户用使用代码基本写完。后面还得添加后台管理内容。

把测试用的私钥两个文件上传到要测试的服务器中,尽量不要放在服务器的目录下。

进入 系统后台 -> 系统设置  -> 支付方式 菜单就可以看到多了一个支付方式,“银联商务”。

在“银联商务”中可以看到最后面一列中有个“安装”链接,点击安装。

ecshop网站添加“银联商务”支付功能_第5张图片

在“商户号”,“商户签名私钥地址”,“ChinaPay签名私钥地址” 中填入测试用的帐户与两个私钥地址。注意一个是公钥(ChinaPay签名私钥地址)一个是私钥(商户签名私钥地址)。再“确定”  到这里安装基本完成。

   剩下的就是测试了。进入网店下单走到支付确认页面中就可以看到多了一个支付选项。选择“银联商务”支付。确认后,会进入跳转支付平台的页面。点“立即使用银联商务支付”就可以进入测试的“银联商务”平台,输入测试用的银行卡号与密码,再提交。测试平台会返回一个测试结果,如果成功等待几秒后会返回到我们的网店确认支付页面。只要这个页面提示支付成功,整个安装过程完成。

   最后是待正式上线时记得修改“商户号”,“商户签名私钥地址”,“ChinaPay签名私钥地址”为正式的内容。