如何在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接口处理解析逻辑:
- 创建.NET Core Web API项目,暴露POST接口接收Base64字符串,调用C#的反序列化方法解析后返回JSON。
- 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有固定字节结构,若序列化对象结构简单,可手动解析解压后的字节流:
- 先用C#反序列化对象,同时打印二进制XML的节点结构和字节偏移信息。
- 在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
相关产品推荐
相关产品推荐

