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

如何在PHP中解析C# NetDataContractSerializer生成的二进制XML数据

问题描述

我在C# .NET应用中使用NetDataContractSerializer结合XmlDictionaryReader.CreateBinaryReader实现二进制XML序列化,生成的数据经Deflate压缩后以Base64字符串存储。目前已在PHP中完成base64_decode解码和gzinflate解压,但无法完成后续的二进制XML解析,求可行的PHP解析方案。


C# 序列化/反序列化代码

序列化(压缩+Base64编码)

public static string SerializeAndCompress(object obj)
{
    using (MemoryStream ms = new MemoryStream())
    {
        using (DeflateStream deflateStream = new DeflateStream(ms, CompressionMode.Compress, true))
        {
            NetDataContractSerializer serializer = new NetDataContractSerializer();
            using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(deflateStream))
            {
                serializer.WriteObject(writer, obj);
            }
        }
        ms.Position = 0;
        return Convert.ToBase64String(ms.ToArray());
    }
}

反序列化(Base64解码+解压+解析)

public static T DeserializeAndDecompress<T>(string base64String)
{
    byte[] compressedData = Convert.FromBase64String(base64String);
    using (MemoryStream ms = new MemoryStream(compressedData))
    {
        using (DeflateStream deflateStream = new DeflateStream(ms, CompressionMode.Decompress))
        {
            NetDataContractSerializer serializer = new NetDataContractSerializer();
            using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(deflateStream, XmlDictionaryReaderQuotas.Max))
            {
                return (T)serializer.ReadObject(reader);
            }
        }
    }
}

示例数据与预期输出

数据库存储的Base64字符串

<此处替换为实际数据库存储的Base64字符串>

预期解析输出(以User对象为例)

{
    "Id": 123,
    "Username": "mureithi",
    "Email": "mureithi@example.com",
    "CreateTime": "2024-05-20T10:30:00"
}

PHP 解析方案

方案1:用.NET Core编写中间服务(生产环境首选)

PHP原生没有解析微软Binary XML格式的库,最可靠的方式是搭建轻量.NET Core接口处理解析逻辑:

  1. 创建.NET Core Web API项目,暴露POST接口接收Base64字符串,调用C#的反序列化方法解析后返回JSON。
  2. PHP通过HTTP请求调用该接口直接获取解析结果。

.NET Core接口示例

[ApiController]
[Route("api/deserialize")]
public class DeserializeController : ControllerBase
{
    [HttpPost]
    public IActionResult Post([FromBody] string base64String)
    {
        try
        {
            var result = DeserializeAndDecompress<object>(base64String);
            return Ok(result);
        }
        catch (Exception ex)
        {
            return BadRequest(ex.Message);
        }
    }

    // 复用之前的DeserializeAndDecompress方法
    public static T DeserializeAndDecompress<T>(string base64String)
    {
        byte[] compressedData = Convert.FromBase64String(base64String);
        using (MemoryStream ms = new MemoryStream(compressedData))
        {
            using (DeflateStream deflateStream = new DeflateStream(ms, CompressionMode.Decompress))
            {
                NetDataContractSerializer serializer = new NetDataContractSerializer();
                using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(deflateStream, XmlDictionaryReaderQuotas.Max))
                {
                    return (T)serializer.ReadObject(reader);
                }
            }
        }
    }
}

PHP调用示例

$base64Str = '<你的Base64字符串>';
$ch = curl_init('http://localhost:5000/api/deserialize');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($base64Str));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

$parsedData = json_decode($response, true);
print_r($parsedData);

方案2:手动解析二进制流(仅适用于简单固定结构)

微软Binary XML有固定字节结构,若序列化对象结构简单,可手动解析解压后的字节流:

  1. 先用C#反序列化对象,同时打印二进制XML的节点结构和字节偏移信息。
  2. 在PHP中按偏移量读取对应数据类型(整数、字符串等)。

PHP手动解析示例(思路)

$base64Str = '<你的Base64字符串>';
$compressed = base64_decode($base64Str);
// DeflateStream生成的压缩数据需跳过前2字节
$decompressed = gzinflate(substr($compressed, 2));

$offset = 0;
// 读取4字节整数类型的Id
$id = unpack('V', substr($decompressed, $offset, 4))[1];
$offset += 4;

// 读取字符串类型的Username(先读长度再读内容)
$usernameLen = unpack('V', substr($decompressed, $offset, 4))[1];
$offset += 4;
$username = substr($decompressed, $offset, $usernameLen);
$offset += $usernameLen;

// 按同样逻辑解析其他字段
$user = [
    'Id' => $id,
    'Username' => $username
];
print_r($user);

注意:手动解析仅适用于固定简单结构,对象结构变化或包含嵌套/集合类型时维护成本极高,不推荐生产环境使用。

内容的提问来源于stack exchange,提问作者Mureithi Maina

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 10:28:30