關於php接ICBC的支付接口的解決方案

一:背景: 目前項目使用的是php語言開發,需要接入中國工商銀行的ICBC的線上支付接口。

 

二:遇到的問題:支付時需要對數據簽名,但是銀行那邊不提供php版本的程序,只有java版本的,以下是對接人回復的郵件:

 

三:思路:

      目前大概有3種解決方案: 

        1.  通過使用一個叫 php-java-bridge 的插件,在php中調用java的函數

        2. 把java的函數改寫成php版本

        3. 在服務器配置javaWeb環境,通過http請求把簽名的參數傳入,從而獲取簽名

 

四: 具體做法:

       我採取的是第3種方法,畢竟對java不太熟悉,不想在語言層面作文章。

       我使用到的是ubuntu14.04 作爲服務器,首先配置javaWeb的環境

       1. 因爲php的環境已經配置好了,所以 php環境的配置環境可以參考: http://www.cnblogs.com/weishuan/p/4402744.html

   2.  tomcat 的環境配置:        

sudo apt update

sudo apt install tomcat7 //安裝tomcat7

sudo apt install default-jdk //javac 編譯

 

安裝好之後,默認的端口是8080,可以通過 http://www.服務器url:8080 驗證

如果需要修改端口號,可以修改 /var/lib/tomcat7/config/server.xml

//原來的配置
<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443"
               maxHttpHeaderSize="102400" />

//修改後的配置
<Connector port="8888(修改後的端口)" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443"
               maxHttpHeaderSize="102400" />

接下來就是java的代碼

getSign.java

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");  //區分是調用哪個函數
        
        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("notifyType");
            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 merCerFileKeyPath = request.getParameter("merCerFileKeyPath");
            String keyPass = request.getParameter("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(), merCerFilePath, keyPass);
            out.print(MerSign);
            
        } else {
            String merCerFileCrtPath = request.getParameter("merCerFileCrtPath");
            String merCertBase64 = getMerCertBase64(merCerFilePath);
            out.print(merCertBase64);
        }
    }
    
    
    
    public static String getMerSignMsgBase64(String tranData,String merCerFilePath,String keyPass) {
        byte[] tranByteSrc = tranData.toString().getBytes();
        char[] keyPasss = keyPass.toCharArray();
        File merSineFile = new File(merCerFilePath);
        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);
            byte[] EncSign = ReturnValue.base64enc(sign);
            String merSignMsgBase64 = new String(EncSign,"UTF-8").toString();
    
            merSignMsgBase64= merSignMsgBase64.replace("\n", "");
            merSignMsgBase64= merSignMsgBase64.replace("\r", "");
            return merSignMsgBase64;
        } catch (Exception e) {
            System.out.println("getMerSignMsgBase64"+e.getMessage());
            e.printStackTrace();
        }
            return "";
        }
    

    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 "";
    }

}

通過http的post或者get方法接收參數,簽名後返回字符串。

 

部署java的代碼,在/var/lib/tomcat7/webapps/目錄下,新建一個icbc的文件夾:

先看web.xml裏面的內容

<?xml version="1.0" encoding="UTF-8"?>
<!--
 Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  version="3.1"
  metadata-complete="true">


  <servlet>
    <!--servlet名称,可以自定义-->
    <servlet-name>icbc</servlet-name>
    <!-- servlet类名: 包名+简单类名-->
    <servlet-class>getSign</servlet-class>
  </servlet>

  <servlet-mapping>
    <!--servlet名称,应与上面的名称保持一致,因为是通过下面的servlet访问名称来定位到上面的servlet名称,再通过上面的名称定位到servlet类的位置-->
    <servlet-name>icbc</servlet-name>
    <!-- servlet的访问名称: /名称 -->
    <url-pattern>/getSign</url-pattern>
  </servlet-mapping>
  

</web-app>

 

 關於getSign.class的編譯,先確保工行的兩個jar包放在lib的目錄里,然後在getSign.java所在的路徑執行以下目錄

javac -cp /var/lib/tomcat7/webapps/icbc/WEB-INF/lib/InfosecCrypto_Java1_02_JDK13+.jar:/var/lib/tomcat7/webapps/icbc/WEB-INF/lib/icbc.jar:/usr/share/tomcat7/lib/servlet-api.jar -d /var/lib/tomcat7/webapps/icbc/WEB-INF/classes/ getSign.java

 

新建一個 /var/www/icbc/ 的文件,把 getSign.java 丟進去,爲了方便,我新建一個腳本文件 javac_icbc.sh

if javac -cp /var/lib/tomcat7/webapps/icbc/WEB-INF/lib/InfosecCrypto_Java1_02_JDK13+.jar:/var/lib/tomcat7/webapps/icbc/WEB-INF/lib/icbc.jar:/usr/share/tomcat7/lib/servlet-api.jar -d /var/lib/tomcat7/webapps/icbc/WEB-INF/classes/ getSign.java
then
        echo "javac -cp /var/lib/tomcat7/webapps/icbc/WEB-INF/lib/InfosecCrypto_Java1_02_JDK13+.jar:/var/lib/tomcat7/webapps/icbc/WEB-INF/lib/icbc.jar:/usr/share/tomcat7/lib/servlet-api.jar -d /var/lib/tomcat7/webapps/icbc/WEB-INF/classes/ getSign.java"

        echo "------  编译成功,重启tomcat 服务器 --------"
        if sudo /etc/init.d/tomcat7 restart
        then
                echo "------ 服务器重启成功 ---------"
        else
                echo "------ 服务器重启失败, 请手动输入下面命令重启 ------"
                echo "sudo /etc/init.d/tomcat7 restart"
        fi
else
        echo "------ 编译失败,请查看 /var/lib/tomcat7/webapps/icbc/WEB-INF/lib/ 文件夹是否存在以下2个文件: --------"
        echo "1. InfosecCrypto_Java1_02_JDK13+.jar"
        echo "2. icbc.jar"
fi

 

 然後添加執行權限:

sudo chmod +x javac_icbc.sh

在執行文件編譯之前,請確保 /var/lib/tomcat7/webapps/icbc/ 具有讀寫權限

sudo chmod -R 777 /var/lib/tomcat7/webapps/icbc/
sudo chmod -R 777 /var/lib/tomcat7/webapps/icbc/*

然後執行javac_icbc.sh

./javac_icbc.sh

 

最後,測試一下環境是否配置成功

 

確保你的公鑰和私鑰都有權限

sudo chmod -R 777 私鑰.key
sudo chmod -R 777 公鑰.crt

 

新建一個index.php文件測試一下:

<?php 
    $interfaceName = "ICBC_MYEBANK_B2C";
    $interfaceVersion = "3.0.0.0";
    $areaCode = "0119";
    $merID = "工行提供";
    $merAcct = "工行提供"";
    $merURL = "你的回調地址";
    $notifyType = "HS";
    $curType = "MOP";
    $resultType = "2";
    $merCerFileKeyPath = "私鑰.key的路徑";
    $merCerFileCrtPath = "公鑰.crt的路徑";
    $keyPass = "12345678";

    $orderid = "201812345678";
    $amount = "1000";//以分爲單位
    $orderDate = "20180123162333";

    $url = "http://localhost:8080/icbc/getSign?type=1&interfaceName=".$interfaceName."&interfaceVersion=".$interfaceVersion."&areaCode=".$areaCode."&merID=".$merID."&merAcct=".$merAcct."&merURL=".$merURL."&notifyType=".$notifyType."&orderid=".$orderid."&amount=".$amount."&curType=".$curType."&resultType=".$resultType."&orderDate=".$orderDate."&merCerFileKeyPath=".$merCerFileKeyPath."&keyPass=".$keyPass;

    $url = "http://localhost:8080/icbc/getSign?merCerFileCrtPath=".$merCerFileCrtPath;




    function _request($url){
        $ch=curl_init();
        curl_setopt($ch,CURLOPT_HEADER,0);
        curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
        curl_setopt($ch,CURLOPT_URL,$url);
        $result=curl_exec($ch);
        curl_close($ch);
        return $result;
    }


echo _request($getBaseUrl);
echo "<br>";
echo "-----------";
echo _request($getSignUrl);

 

最後能獲取簽名:

 

最後的最後 :

在開發過程中,我遇到了一個問題, 通過post或者get 方法時,傳遞的參數過多,超出tomcat的緩衝區,目前還沒解決。

org.apache.coyote.http11.AbstractHttp11Processor process
信息: Error parsing HTTP request header
Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.

 

百度和google 發現是:Tomcat的header缓冲区大小不够,只需要在server.xml中增加maxHttpHeaderSize字段即可

但是我加了還是報錯,無奈只能把post的參數減少,把固定的參數寫死在java文件中。

posted @ 2018-01-28 18:42  HaHahahahaaaa  阅读(1177)  评论(1编辑  收藏  举报