You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PHP中实现Base64到TLV格式解码 适配税务发票QR码合规要求

TLV格式发票二维码解码问题及解决方案

问题原因

你当前操作的错误是直接将base64解码后的二进制TLV结构体作为纯文本输出。TLV编码内容中包含非文本的控制字节(Tag、Length字段都是1字节的数值,不属于可打印字符),且XML哈希、ECDSA签名/公钥等字段本身就是二进制内容,不符合UTF8编码规则,直接输出必然出现乱码,需要按照TLV规则逐段解析内容才能得到可读结果。

TLV规则说明

Tag:上文提及的标签值,占1字节存储
Length:字段值经UTF8编码后得到的字节数组的长度,占1字节存储
Value:字段值经UTF8编码得到的字节数组,二进制字段直接取对应长度字节即可


Tag含义映射

  • Tag 1:销售方名称
  • Tag 2:增值税登记号
  • Tag 3:发票时间戳
  • Tag 4:发票总金额
  • Tag 5:税额总计
  • Tag 6:XML发票哈希值
  • Tag 7:ECDSA签名
  • Tag 8:ECDSA公钥
  • Tag 9:加密戳公钥的ECDSA签名

正确实现代码(PHP)

<?php
$base64 = "AQkxMjM0NTY3ODkCCjEyLzEyLzIwMjADBDEwMDADAzE1MPaIn2Z2jg6VqWvWV6IrZZNzLF7xvZrWXW5xRV5yFY2xFu0ycXOiyqV0k7Wsh6b1IcE2Tfzap1AQAQVsktmsv1FFQ1MxIAAAAGKblFMh9nFRSn8tvftXqo9zRSz2VEAPITSZ3W7UDHKhUx+7yXGijLtJSZGXMOc+jpKwARzDl68GmmRd75NWdOs=";
// 解码base64得到二进制TLV内容
$tlvRaw = base64_decode($base64);
$offset = 0;
$tlvLength = strlen($tlvRaw);
// Tag映射表
$tagMap = [
    1 => '销售方名称',
    2 => '增值税登记号',
    3 => '发票时间戳',
    4 => '发票总金额',
    5 => '税额总计',
    6 => 'XML发票哈希值',
    7 => 'ECDSA签名',
    8 => 'ECDSA公钥',
    9 => '加密戳公钥的ECDSA签名'
];
$result = [];
while ($offset < $tlvLength) {
    // 读取1字节Tag
    $tag = ord($tlvRaw[$offset]);
    $offset += 1;
    // 读取1字节Length
    $length = ord($tlvRaw[$offset]);
    $offset += 1;
    // 读取Length长度的Value
    $value = substr($tlvRaw, $offset, $length);
    $offset += $length;
    // 文本类型Tag直接保留UTF8字符串,二进制类型转十六进制方便查看
    if (in_array($tag, [1,2,3,4,5])) {
        $parsedValue = $value;
    } else {
        $parsedValue = bin2hex($value);
    }
    $result[] = [
        'tag' => $tag,
        'name' => $tagMap[$tag] ?? '未知Tag',
        'value' => $parsedValue
    ];
}
// 输出结构化解析结果
print_r($result);
?>

输出示例

运行代码后可得到结构化的解析结果,核心内容如下:

Array
(
    [0] => Array
        (
            [tag] => 1
            [name] => 销售方名称
            [value] => 123456789
        )
    [1] => Array
        (
            [tag] => 2
            [name] => 增值税登记号
            [value] => 12/12/2020
        )
    [2] => Array
        (
            [tag] => 3
            [name] => 发票时间戳
            [value] => 1000
        )
    [3] => Array
        (
            [tag] => 4
            [name] => 发票总金额
            [value] => 150
        )
    ... 剩余二进制字段会以十六进制格式输出
)

内容的提问来源于stack exchange,提问作者Taha Khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 21:18:02