PHP 对接ICBC支付的经验分享

概述:

最近在做一个澳门的商城项目,其中需要跟当地的工商银行对接支付,其中的提交支付时,工商银行的加密有自己加密程序,然而他们只提供了JAVA和C 语言的DEMO,并没有PHP的DEMO,甚至连PHP的扩展也说没有,一时让我陷入了困境,不知道怎解决,于是我在百度 谷歌上寻找解决方法。

问题解决方案:

1、java版本的domo用PHP重写

其实这澳门提供的接口的加密方式跟国内大陆的一致,也是用infosec扩展的程序进行加密,大陆的一些开发人员对接接口是直接把JAVA转化成PHP,不过必须的当然是相关的PHP扩展。不过,让我失望的是,当我问工作人员有没有PHP扩展时,他却一问三不知,只有JAVA版本的。而网友分享的PHP拓展,一来不安全,二来只有PHP5.6的版本,而我们服务器已经升级到PHP7了,不知道能否兼容。因此,保守起见,最终放弃了该做法。
(该方法可参考链接:https://blog.csdn.net/weixin_41750160/article/details/83341199)

2、调用java接口进行加密

既然他们提供了java的demo,其实应用起来也不难。但是需要的是搭建javaWeb的环境,并且把demo部署好,我们让php程序加密时候调用一下自己的做的java 加密接口就好了。最终,我选择了该方法。
(该方法可参考链接:https://www.cnblogs.com/weishuan/p/8372063.html)

搭建java接口过程:

1、安装tomcat

该过程不熟悉的朋友,可以按照教程一步步来,值得注意的是,tomcat的端口是8080,其实根据我们的需求,我们只需要自己的PHP程序所在服务器能请求到就行,也就是说localhost能访问或者固定IP就好了,以防给黑客多一个攻击的入口,因此该端口可以不开放或者限制IP访问。
可以参考https://blog.csdn.net/lcyaiym/article/details/76696192

2、部署java项目

其实工商银行对接人一般会提供接口介绍的PPT给你,有加密方法的demo,但是也还没达到开箱即用的程度,因此我分享一下我自己的写的java demo给大家参考。请根据自己的文件路径进行修改,注释部分是调试的,如果返回不成功,可以去掉注释进行分步调试。

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.com.infosec.icbc.ReturnValue;



/**
 * Servlet implementation class getSign
 */
@WebServlet("/getSign")
public class getSign extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public getSign() {
        super();
    }


    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        
        doPost(request,response);
    }

    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
        PrintWriter out = response.getWriter();
        String type  = request.getParameter("type");  //區分是調用哪個函數
        String merCerFileKeyPath = "/var/www/opencart/v3.0/signicbc/icbcOpayTest.key"; //商户秘钥所在绝对路径
        String merCerFileCrtPath = "/var/www/opencart/v3.0/signicbc/icbcOpayTest.crt"; //商户证书所在绝对路径    
        
        if (type != null) {
            
            String interfaceName = request.getParameter("interfaceName");
            String interfaceVersion = request.getParameter("interfaceVersion");
            String areaCode = request.getParameter("areaCode");
            String merID = request.getParameter("merID");
            String merAcct = request.getParameter("merAcct");
            String merURL = request.getParameter("merURL");
            String notifyType = request.getParameter("nType");
            String orderid = request.getParameter("orderid");
            String amount = request.getParameter("amount");
            String curType = request.getParameter("curType");
            String resultType = request.getParameter("resultType");
            String orderDate = request.getParameter("orderDate");
            String keyPass = request.getParameter("keyPass");
			
		/*
			 out.println("---interfaceName" + interfaceName);
			 out.println("---interfaceVersion" + interfaceVersion);
			 out.println("---areaCode" + areaCode);
			 out.println("---merID" + merID);
			 out.println("---merAcct" + merAcct);
			 out.println("---merURL" + merURL);
			 out.println("---notifyType" + notifyType);
			 out.println("---orderid" + orderid);
			 out.println("---amount" + amount);
			 out.println("---curType" + curType);
			 out.println("---resultType" + resultType);
			 out.println("---orderDate" + orderDate);
			 out.println("---keyPass" + keyPass);
		*/	 

            StringBuilder tranData = new StringBuilder(); 
            tranData.append(interfaceName).append(interfaceVersion).append(areaCode).append(merID).append(merAcct).append(merURL).append(notifyType).append(orderid).append(amount).append(curType).append(resultType).append(orderDate);
            
            //String MerSign = getMerSignMsgBase64(tranData.toString(), merCerFileCrtPath, keyPass);StringBuilder 
            //out.println("IcbcOpayFileReader.getMerSignMsgBase64:"+tranData.toString());
            byte[] tranByteSrc = tranData.toString().getBytes();
            char[] keyPasss = keyPass.toCharArray();
            File merSineFile = new File(merCerFileKeyPath);

            FileInputStream fileInputStream;
            try {
            fileInputStream = new FileInputStream(merSineFile.getAbsolutePath());
            byte[] sineBytes = new byte[fileInputStream.available()];
            fileInputStream.read(sineBytes);
            fileInputStream.close();
            byte[] sign =ReturnValue.sign(tranByteSrc,tranByteSrc.length,sineBytes,keyPasss);
            if(sign ==null){
                out.println("-----sign return is null");
                out.println("-----sign tranByteSrc.length is"+tranByteSrc.length);
                out.println("-----sign keyPasss is"+keyPasss);
                
            }
            byte[] EncSign = ReturnValue.base64enc(sign);
            String merSignMsgBase64=new String(EncSign,"UTF-8").toString();

            merSignMsgBase64= merSignMsgBase64.replace("\n", "");
            merSignMsgBase64= merSignMsgBase64.replace("\r", "");
            out.print(merSignMsgBase64);
            } catch (Exception e) {
            System.out.println("getMerSignMsgBase64"+e.getMessage());
            e.printStackTrace();
            }
            
        }else {
            String merCertBase64 = getMerCertBase64(merCerFileCrtPath);
            out.print(merCertBase64);
        }
    }
    
    

    public static String getMerCertBase64(String merCerFilePath) {

        File merCerFile = new File(merCerFilePath);
        FileInputStream fileInputStream;
        
        try {
            fileInputStream = new FileInputStream(merCerFile.getAbsolutePath());
            System.out.println(merCerFile.getAbsolutePath());
            byte[] bytes = new byte[fileInputStream.available()];
            fileInputStream.read(bytes);
            fileInputStream.close();
            byte[] EncCerts=ReturnValue.base64enc(bytes);
            String merCertBase64=new String(EncCerts).toString();
            merCertBase64= merCertBase64.replace("\n", "");
            merCertBase64= merCertBase64.replace("\r", "");
            System.out.println("IcbcOpayFileReader.getMerCertBase64:"+merCertBase64);
            return merCertBase64;
        } catch (FileNotFoundException e) {
            System.out.println("getMerCertBase64"+e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        return "";
    }
	
	private String getParameter(HttpServletRequest request, String paramString)
    {
    	String param = paramString.replace("&","");
        String v = request.getParameter(param);
        if (v == null)
            v="";
        System.out.println(paramString + "=" + v);
        return paramString + "=" + v + "&";
    }
	
	
	private String verifySign(String msg, String signMsg, String pubKeyFile){
		String ENCODING = "utf-8";
		try
		{
			// 读取工行的公钥
			FileInputStream fileKey = new FileInputStream(pubKeyFile);
			byte[] cert = new byte[fileKey.available()];
			fileKey.read(cert);
			fileKey.close();


			// 读取明文,密文
			byte[] byteSrc = msg.getBytes(ENCODING);
			byte[] sign = ReturnValue.base64dec(signMsg.getBytes(ENCODING));


			// 验证,正常返回0,失败返回1
			int verifySign = ReturnValue.verifySign(byteSrc, byteSrc.length, cert, sign);


			System.out.println("RetCode = " + verifySign);


			if (verifySign == 0)
				return "true";


			return "verify_false"+verifySign;
		} catch (Exception e){
			e.printStackTrace();
			return "try_false";
		}
	}
	
}
	
	
	



3、加密接口调用

请求工商银行的支付接口时,主要加密的两个参数主要是订单签名数据和商城证书公钥,我的java接口demo中,传参type=1时是指订单签名数据加密(同时需要传入加密订单参数),而不传type值时,是指商城证书公钥加密。
例子如下:
订单签名数据加密:

 http://localhost:8080/icbc/getSign?type=1&interfaceName=ICBC_MYEBANK_B2C&interfaceVersion=3.0.0.0&areaCode=0119&merID=0119EC20000741&merAcct=0119100000001017824&merURL=http://www.test.com/test123&nType=HS&orderid=20190716121050883909&amount=1230&curType=MOP&resultType=1&orderDate=20190716121050&keyPass=12345678

商城证书公钥加密:

 http://localhost:8080/icbc/getSign

返回内容均为base64格式的加密内容。

4、整合数据请求支付接口

最后,用PHP整合请求支付接口进行支付页面跳转,在此我也提供我的测试demo给大家参考。
(下载地址:https://download.csdn.net/download/tim_phper/11364454)

总结:

其实跨语言也没有想象中那么困难,动手试一试,你可以能会发现其实也很容易。过程可能遇到很多坑,可是你会发现收获真的不少的!

你可能感兴趣的:(PHP)