由于需求要求从一个php项目的mysql数据 将一些基础数据迁移到net项目下的mssql数据库下
遇到个问题 第三方提供存储在数据库的数据对象是 php序列化后的 需要将数据转换为net 可以用的
写个demo 程序构成
data.txt 存储的php序列化字符 后续可以根据自己需求进行数据库的数据读取
PhpSerializer.cs 核心关键代码 反序列化php字符串为数据对象
Program.cs 主程序入口
附上源码
data.txt
a:5:{i:0;a:7:{s:2:\"id\";s:1:\"1\";s:4:\"text\";s:3:\"好\";s:5:\"score\";s:3:\"100\";s:8:\"sort_num\";i:1;s:10:\"isNegative\";N;s:3:\"min\";N;s:3:\"max\";N;}i:1;a:7:{s:2:\"id\";s:1:\"2\";s:4:\"text\";s:6:\"较好\";s:5:\"score\";s:2:\"80\";s:8:\"sort_num\";i:2;s:10:\"isNegative\";N;s:3:\"min\";N;s:3:\"max\";N;}i:2;a:7:{s:2:\"id\";s:1:\"3\";s:4:\"text\";s:6:\"一般\";s:5:\"score\";s:2:\"60\";s:8:\"sort_num\";i:3;s:10:\"isNegative\";N;s:3:\"min\";N;s:3:\"max\";N;}i:3;a:7:{s:2:\"id\";s:1:\"4\";s:4:\"text\";s:6:\"较差\";s:5:\"score\";s:2:\"40\";s:8:\"sort_num\";i:4;s:10:\"isNegative\";N;s:3:\"min\";N;s:3:\"max\";N;}i:4;a:7:{s:2:\"id\";s:1:\"5\";s:4:\"text\";s:3:\"差\";s:5:\"score\";s:1:\"0\";s:8:\"sort_num\";i:5;s:10:\"isNegative\";N;s:3:\"min\";N;s:3:\"max\";N;}}
PhpSerializer.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace PhpSerializerNETDemo
{
public class PhpSerializer
{
//types:
// N = null
// s = string
// i = int
// d = double
// a = array (hashtable)
private Dictionary<Hashtable, bool> seenHashtables;
private Dictionary<ArrayList, bool> seenArrayLists;
private int pos;
public bool XMLSafe = true;
//http://www.w3.org/TR/REC-xml/#sec-line-ends
public Encoding StringEncoding = new System.Text.UTF8Encoding();
private System.Globalization.NumberFormatInfo nfi;
public PhpSerializer()
{
this.nfi = new System.Globalization.NumberFormatInfo();
this.nfi.NumberGroupSeparator = "";
this.nfi.NumberDecimalSeparator = ".";
}
public string Serialize(object obj)
{
this.seenArrayLists = new Dictionary<ArrayList, bool>();
this.seenHashtables = new Dictionary<Hashtable, bool>();
return this.serialize(obj, new StringBuilder()).ToString();
}
private StringBuilder serialize(object obj, StringBuilder sb)
{
if (obj == null)
{
return sb.Append("N;");
}
else if (obj is string)
{
string str = (string)obj;
if (this.XMLSafe)
{
str = str.Replace("\r\n", "\n");//replace \r\n with \n
str = str.Replace("\r", "\n");//replace \r not followed by \n with a single \n Should we do this?
}
return sb.Append("s:" + this.StringEncoding.GetByteCount(str) + ":\"" + str + "\";");
}
else if (obj is bool)
{
return sb.Append("b:" + (((bool)obj) ? "1" : "0") + ";");
}
else if (obj is int)
{
int i = (int)obj;
return sb.Append("i:" + i.ToString(this.nfi) + ";");
}
else if (obj is double)
{
double d = (double)obj;
return sb.Append("d:" + d.ToString(this.nfi) + ";");
}
else if (obj is ArrayList)
{
if (this.seenArrayLists.ContainsKey((ArrayList)obj))
return sb.Append("N;");//cycle detected
else
this.seenArrayLists.Add((ArrayList)obj, true);
ArrayList a = (ArrayList)obj;
sb.Append("a:" + a.Count + ":{");
for (int i = 0; i < a.Count; i++)
{
this.serialize(i, sb);
this.serialize(a[i], sb);
}
sb.Append("}");
return sb;
}
else if (obj is Hashtable)
{
if (this.seenHashtables.ContainsKey((Hashtable)obj))
return sb.Append("N;");//cycle detected
else
this.seenHashtables.Add((Hashtable)obj, true);
Hashtable a = (Hashtable)obj;
sb.Append("a:" + a.Count + ":{");
foreach (DictionaryEntry entry in a)
{
this.serialize(entry.Key, sb);
this.serialize(entry.Value, sb);
}
sb.Append("}");
return sb;
}
else
{
return sb;
}
}//Serialize(object obj)
public object Deserialize(string str)
{
this.pos = 0;
return deserialize(str);
}//Deserialize(string str)
private object deserialize(string str)
{
if (str == null || str.Length <= this.pos)
return new Object();
int start, end, length;
string stLen;
switch (str[this.pos])
{
case 'N':
this.pos += 2;
return null;
case 'b':
char chBool;
chBool = str[pos + 2];
this.pos += 4;
return chBool == '1';
case 'i':
string stInt;
start = str.IndexOf(":", this.pos) + 1;
end = str.IndexOf(";", start);
stInt = str.Substring(start, end - start);
this.pos += 3 + stInt.Length;
return Int64.Parse(stInt, this.nfi);
case 'd':
string stDouble;
start = str.IndexOf(":", this.pos) + 1;
end = str.IndexOf(";", start);
stDouble = str.Substring(start, end - start);
this.pos += 3 + stDouble.Length;
return Double.Parse(stDouble, this.nfi);
case 's':
start = str.IndexOf(":", this.pos) + 1;
end = str.IndexOf(":", start);
stLen = str.Substring(start, end - start);
int bytelen = Int32.Parse(stLen);
length = bytelen;
//This is the byte length, not the character length - so we migth
//need to shorten it before usage. This also implies bounds checking
if ((end + 2 + length) >= str.Length) length = str.Length - 2 - end;
string stRet = str.Substring(end + 2, length);
while (this.StringEncoding.GetByteCount(stRet) > bytelen)
{
length--;
stRet = str.Substring(end + 2, length);
}
this.pos += 6 + stLen.Length + length;
if (this.XMLSafe)
{
stRet = stRet.Replace("\n", "\r\n");
}
return stRet;
case 'a':
//if keys are ints 0 through N, returns an ArrayList, else returns Hashtable
start = str.IndexOf(":", this.pos) + 1;
end = str.IndexOf(":", start);
stLen = str.Substring(start, end - start);
length = Int32.Parse(stLen);
Hashtable htRet = new Hashtable(length);
ArrayList alRet = new ArrayList(length);
this.pos += 4 + stLen.Length; //a:Len:{
for (int i = 0; i < length; i++)
{
//read key
object key = deserialize(str);
//read value
object val = deserialize(str);
if (alRet != null)
{
if (key is int && (int)key == alRet.Count)
alRet.Add(val);
else
alRet = null;
}
htRet[key] = val;
}
this.pos++; //skip the }
if (this.pos < str.Length && str[this.pos] == ';')//skipping our old extra array semi-colon bug (er... php's weirdness)
this.pos++;
if (alRet != null)
return alRet;
else
return htRet;
default:
return "";
}//switch
}//unserialzie(object)
}//class Serializer
}
Program.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PhpSerializerNETDemo
{
class Program
{
static void Main(string[] args)
{
var dataFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data.txt");
var serializerString = File.ReadAllText(dataFilePath);
serializerString = serializerString.Replace("\\", "");
var result = PhpSerializerNET.PhpSerialization.Deserialize(serializerString);
Console.WriteLine(result);
}
}
}