[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: php compatible unserialise in lua?
- From: Michal Kolodziejczyk <miko@...>
- Date: Tue, 25 Sep 2007 12:23:38 +0200
XIX wrote:
> Hi,
>
> I find myself in need of handling some data thats been serialized in
> php, using the native serialize function.
>
> I was hoping there would be a tried and tested lua library to do such
> a thing available somewhere. Unfortunately after some searching I've
> not found anything so my last act is to ask on this list before I sit
> down and write it.
>
> http://www.phpguru.org/static/PHP_Unserialize.html#other
>
> Is my best find so far which as you can tell contains links to
> versions in a few languages that are not lua :)
>
> Can anyone point me to a php unserializer written in lua?
Hi, I neither could find a php serializer/unserializer in lua, so I
ported a python one I found here (make sure to read about it):
http://www.hurring.com/scott/code/python/serialize/
I have not finished it yet (objects cannot be unserialized), but should
work for simple cases. I hope it will help you start.
Regards,
miko
================== CUT HERE =====================================
------- PHPSerialize.lua -------
module("PHPSerialize", package.seeall)
local MT={__index=_M}
function init(self)
end
function new()
local o={}
setmetatable(o, MT)
return o
end
function serialize(self, data)
return self:serialize_value(data)
end
function is_int(self, data)
if tonumber(data) then
return true
else
return false
end
--[[
if type(data)=='number' and math.floor(data)==data then
return true
else
return false
end
]]--
end
function serialize_key(self, data)
if type(data)=='number' then
return 'i:'..data..';'
end
if type(data)=='boolean' then
return 'i:1'
end
if type(data)=='string' then
if self:is_int(data) then
return 'i:'..tonumber(data)..';'
else
return 's:'..string.len(data)..':"'..data..'";'
end
end
if type(data)=='nil' then
return 's:0:"";'
end
error('Unknown/Unhandled key type! type='..type(data))
end
function serialize_value(self, data)
if type(data)=='number' then
if math.floor(data)==data or math.ceil(data)==data then
return 'i:'..data..';'
else
return 'd:'..data..';'
end
end
if type(data)=='string' then
if self:is_int(data) then
return 'i:'..tonumber(data)..';'
else
return 's:'..string.len(data)..':"'..data..'";'
end
end
if type(data)=='nil' then
return 'N;'
end
if type(data)=='table' then
local out={}
local i=0
local len=0
if #data>0 then
for k,v in pairs(data) do
if self:is_int(k) then
table.insert(out, self:serialize_key(i))
else
table.insert(out, self:serialize_key(k))
i=i-1
end
table.insert(out, self:serialize_value(v))
i=i+1
len=len+1
end
else
for k,v in pairs(data) do
table.insert(out, self:serialize_key(k))
table.insert(out, self:serialize_value(v))
len=len+1
end
end
return 'a:'..len..':{'..table.concat(out)..'}'
end
if type(data)=='boolean' then
if data then
return 'b:1;'
else
return 'b:0;'
end
end
error('Unknown / Unhandled data type! type='..type(data))
end
function unserialize(self, data)
local a,b,c = self:_unserialize(data, 0)
return c
end
function _unserialize(self, data, offset)
if offset==nil then offset=0 end
local buf={}
local dtype=string.lower(string.sub(data,offset+1,offset+1))
local dataoffset=offset+2
local typeconvert=function(x) return x end
local chars,datalength=0,0
local readdata, stringlength=nil,nil
local s1=offset-5
if s1<1 then s1=1 end
local s2=offset+5
if s2>string.len(data) then s2=string.len(data) end
local snip=string.sub(data, s1,s2)
if dtype=='i' then
typeconvert=function(x) return tonumber(x) end
chars, readdata=self:read_until(data, dataoffset, ';')
dataoffset=dataoffset+chars+1
elseif dtype=='b' then
typeconvert=function(x) return tonumber(x)==1 end
chars, readdata=self:read_until(data, dataoffset, ';')
dataoffset=dataoffset+chars+1
elseif dtype=='d' then
typeconvert=function(x) return tonumber(x) end
chars, readdata=self:read_until(data, dataoffset, ';')
dataoffset=dataoffset+chars+1
elseif dtype=='n' then
readdata=nil
elseif dtype=='s' then
chars, stringlength=self:read_until(data, dataoffset, ':')
dataoffset=dataoffset+chars+2
chars, readdata=self:read_chars(data, dataoffset+1,
tonumber(stringlength
))
dataoffset=dataoffset+chars+2
if chars~=tonumber(stringlength) or chars~=string.len(readdata) then
error('String len mismatch!')
end
elseif dtype=='a' then
readdata={}
local keys=nil
chars, keys=self:read_until(data, dataoffset, ':')
dataoffset=dataoffset+chars+2
for i=0,tonumber(keys)-1 do
local ktype, kchars, key=self:_unserialize(data, dataoffset)
dataoffset=dataoffset+kchars
local vtype, vchars, value=self:_unserialize(data, dataoffset)
dataoffset=dataoffset+vchars
readdata[key]=value
end
dataoffset=dataoffset+1
elseif dtype=='o' then
chars, stringlength=self:read_until(data, dataoffset, ':')
dataoffset=dataoffset+chars+2
chars, readdata=self:read_chars(data, dataoffset+1,
tonumber(stringlength
))
dataoffset=dataoffset+chars+2
if chars~=tonumber(stringlength) or chars~=string.len(readdata) then
error('String len mismatch!')
end
readdata=self:createClass(readdata) or {CLASSNAME=readdata} --new
class
local keys=nil
chars, keys=self:read_until(data, dataoffset, ':')
dataoffset=dataoffset+chars+2
for i=0,tonumber(keys)-1 do
local ktype, kchars, key=self:_unserialize(data, dataoffset)
dataoffset=dataoffset+kchars
local vtype, vchars, value=self:_unserialize(data, dataoffset)
dataoffset=dataoffset+vchars
readdata[key]=value
end
dataoffset=dataoffset+1
else
error('"Unknown / Unhandled data type! type='..dtype)
end
return dtype, dataoffset-offset, assert(typeconvert)(readdata)
end
function read_until(self, data, offset, stopchar)
local buf={}
local char=string.sub(data, offset+1, offset+1)
local i=2
while char~=stopchar do
if i+offset>string.len(data) then
error('Invalid')
end
table.insert(buf, char)
char=string.sub(data, offset+i, offset+i)
i=i+1
end
return #buf, table.concat(buf)
end
function read_chars(self, data, offset, length)
local buf={}
for i=1,length do
char=string.sub(data, offset+(i-1), offset+(i-1))
table.insert(buf, char)
end
return #buf, table.concat(buf)
end
-- TODO: not implemented yet!
function createClass(self, classname)
return {DummyClass=classname}
end
--------- test.lua -------------
require 'PHPSerialize'
P=PHPSerialize:new()
print(P:serialize_key(1))
print(P:serialize_key('AS'))
print(P:serialize_key(nil))
a={1,2,3,4, 'five', six='six' , seven={1,2}}
ll=P:serialize(a)
print (ll)
x=P:unserialize(ll)
print('X='..type(x))
for k,v in pairs(x) do print(k,v) end