php 生成国税局二维码

         今天是在公司的最后一天,早上完成工作后大佬还没时间给我安排新的工作,现在就有点时间来写下博客了,前段时间都没写的博客,哎!感觉这个习惯很难养成。

         今天来讲讲之前做的一个东西,就是要生成国税局的发票二维码,即 使用程序代码生成相应信息的二维码需要跟 税局发票助手 生成的二维码携带的信息是一样的。我使用的是 php 语言,一开始就上网百度了下 php 生成二维码的方法,一下子就能找出 phpqrcode 这个库(地址:http://phpqrcode.sourceforge.net/),下载后直接引入主要的文件 phpqrcode.php 再百度下 demo 代码即可生成(带 logo 的二维码),当然如果是生成普通的二维码的话上面就可以了,但是生成国税局发票的二维码还是不简单滴,涉及到 了 CRC-16 加密算法,百度了一篇博文讲解了国税总局发票助手二维码生成的CRC计算和便捷开票二维码编码内容格式,点击打开链接,如下图:

php 生成国税局二维码_第1张图片

可以看出,最最主要的就是计算这个 CRC 了,不过上面的这篇博文给出的代码不仅是 java 版本的,关键的是代码不完整,变量初值没给出来。这就很尴尬了。于是继续百度,发现 php 官网上有计算 crc16 的算法例子(点击打开链接),或直接见以下代码(我只拿了其中一份简洁的代码例子如下):

> 1) ^ 0xA001); 
      } else { 
          $crc = $crc >> 1; 
      } 
    } 
  } 
  return $crc; 
} 
?> 

于是迫不及待尝试计算存储在二维码中的信息构成的 crc16 的值,结果计算出来的始终与 税局发票助手(可以下载然后用来测试)生成的 crc16 不一样。。还是贴下测试的代码:

> 1) ^ 0xA001); 
      } else { $crc = $crc >> 1; } 
    } 
  } 
  return $crc; 
}

$string = '广东xx网络有限公司91442000***3中山市石岐区xxx 0760-88888888中国建设银行中山兴中道支行 4400***0';

$s = @pack('H*', $string);
$t = @crc16($s);
@printf('%02x%02x', $t%256, floor($t/256));

狠尴尬。。百度了好久也不造确切原因额。。

接下来只能寄希望于最初那篇博文的源代码了,于是继续百度百度百度,最后终于找到了一个说根据那段残缺代码然后去测试,慢慢推出来了那两个变量的初值,不容易啊!牛~花了2积分下了他的代码自行研究,毕竟是 java 版本的,还是得改成 php 版本的先。

主要的 java 版本的代码如下所示:

public class TestCrc  {

	public static void main(String[] args){
		  
		String input = "北京国税1234567899XXxx123456789XXxx北京市通州区正在大厦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;  
    }  	
}
只能使用上述的生成 crc16 的算法了,经过研究改成 php 版本的代码如下:

                        $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";	
	$qrcodeContent = TestCrc::test($content);
结果发现结果还是与税局发票助手的生成的 crc16 结果不一样,后来一想直接不要将输入的内容转 gbk 格式试试看,结果就可以了,主要将上述代码修改如下:

修改 test 函数的前两行代码为:

      $inputs = self::getBytes($input);
即可顺利生成与税局发票助手一致的二维码了(存储的 base64 内容一致)。快去试试吧!

感觉很多东西一开始很陌生,会有种惧怕的感觉,但是一旦尝试深入解决,只要坚持,我相信大部分(不可能是全部)难题都可以被你解决的!

好了,Java 版本的代码地址如下:

点击打开链接

php 版本的 demo 地址如下:

点击打开链接









你可能感兴趣的:(PHP)