可以看出,最最主要的就是计算这个 CRC 了,不过上面的这篇博文给出的代码不仅是 java 版本的,关键的是代码不完整,变量初值没给出来。这就很尴尬了。于是继续百度,发现 php 官网上有计算 crc16 的算法例子(点击打开链接),或直接见以下代码(我只拿了其中一份简洁的代码例子如下):
public class TestCrc {
public static void main(String[] args){
String input = "北京国税123456789</>9XXxx123456789XXxx</>北京市通州区正在大厦123456789</>中国银行123456789</>";
try {
byte[] inputs = input.getBytes("GBK");
for (int i = 0; i < inputs.length; i ++) {
div(inputs[i]);
}
byte r = 0;
div(r);
div(r);
String crc3=Integer.toHexString(a);
System.out.println(Integer.toHexString(a));
String jm=getBase64(input+crc3.toUpperCase());//base64加密
String s="$01"+jm+"$";
String a="5YyX5Lqs5Zu956iOMTIzNDU2Nzg5PC8+OVhYeHgxMjM0NTY3ODlYWHh4PC8+5YyX5Lqs5biC6YCa5bee5Yy65q2j5Zyo5aSn5Y6mMTIzNDU2Nzg5PC8+5Lit5Zu96ZO26KGMMTIzNDU2Nzg5PC8+MjAxQQ==";
System.out.println(s);
String jmh1=getFromBase64(a);
System.out.println(jmh1);
} catch (Exception e) {
e.printStackTrace();
}
}
static int a=0x0000;
static int crc16=0x8005;
private static void div(byte input) {//算法
int temp=0;
int data = input;
for (int i = 0; i < 8; i ++) {
temp = a & 0x8000;
a = a << 1;
a = a & 0x0000ffff;
int numIn = data & 0x80;
numIn = numIn >> 7;
a = a ^ numIn;
if (temp == 0x8000) {
a = a ^ crc16;
}
data = data << 1;
a = a & 0x0000ffff ;
}
}
public static String getBase64(String str) { //加密
byte[] b = null;
String s = null;
try {
b = str.getBytes("utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if (b != null) {
s = new BASE64Encoder().encode(b);
}
return s;
}
public static String getFromBase64(String s) { //解密
byte[] b = null;
String result = null;
if (s != null) {
BASE64Decoder decoder = new BASE64Decoder();
try {
b = decoder.decodeBuffer(s);
result = new String(b, "utf-8");
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
}
}
class TestCrc {
public static function getBytes($string) {/* 获取字节流数组(ASCII码) */
$bytes = array();
for($i = 0; $i < strlen($string); $i++){
$bytes[] = ord($string[$i]);
}
return $bytes;
}
public static function test($input){/* 传递参数为填写在国税发票助手的内容拼成的二维码存储内容格式,返回的是存入二维码的内容 */
$inputs = iconv('utf-8', 'gbk', $input);
$inputs = array_map('ord', str_split($inputs));
for ($i = 0; $i < count($inputs); $i++) {
self::div($inputs[$i]);
}
$r = 0;
self::div($r);
self::div($r);
$crc = sprintf("%04X",self::$a); /* 输出4位16进制数(不足四位用0占位) */
$QRcodeContent = $input.$crc;
return '$01'.base64_encode($QRcodeContent).'$';
}
public static $a=0x0000;
public static $crc16=0x8005;
private static function div($input) {/* 算法 */
$temp=0;
$data = $input;
for ($i = 0; $i < 8; $i ++) {
$temp = self::$a & 0x8000;
self::$a = self::$a << 1;
self::$a = self::$a & 0x0000ffff;
$numIn = $data & 0x80;
$numIn = $numIn >> 7;
self::$a = self::$a ^ $numIn;
if ($temp == 0x8000) {
self::$a = self::$a ^ self::$crc16;
}
$data = $data << 1;
self::$a = self::$a & 0x0000ffff ;
}
}
测试代码:
$content = "广东xx网络有限公司</>91442000***3</>中山市石岐区xxx 0760-88888888</>中国建设银行中山兴中道支行 4400***0</>";
Content = TestCrc::test($content);
结果发现结果还是与税局发票助手的生成的 crc16 结果不一样,后来一想直接不要将输入的内容转 gbk 格式试试看,结果就可以了,主要将上述代码修改如下:
修改 test 函数的前两行代码为:
即可顺利生成与税局发票助手一致的二维码了(存储的 base64 内容一致)。快去试试吧!
感觉很多东西一开始很陌生,会有种惧怕的感觉,但是一旦尝试深入解决,只要坚持,我相信大部分(不可能是全部)难题都可以被你解决的!