@@ -15,6 +15,28 @@ def read_until(char)
1515 end
1616 end
1717
18+ module SerializationState
19+ class Base
20+ # @return [Boolean]
21+ attr_accessor :assoc
22+ end
23+
24+ class ToSerialize < Base
25+ end
26+
27+ class ToUnserialize < Base
28+ def initialize
29+ @classmap = { }
30+ end
31+
32+ # @return [Hash{String => Class}]
33+ attr_accessor :classmap
34+
35+ # @return [String]
36+ attr_accessor :original_encoding
37+ end
38+ end
39+
1840 # Returns a string representing the argument in a form PHP.unserialize
1941 # and PHP's unserialize() should both be able to load.
2042 #
@@ -29,17 +51,24 @@ def read_until(char)
2951 # array will be assumed to be an associative array, and will be serialized
3052 # as a PHP associative array rather than a multidimensional array.
3153 def PHP . serialize ( var , assoc = false ) # {{{
54+ state = SerializationState ::ToSerialize . new . tap { |state |
55+ state . assoc = assoc
56+ }
57+ do_serialize ( var , state )
58+ end
59+
60+ def PHP . do_serialize ( var , state )
3261 s = String . new
3362 case var
3463 when Array
3564 s << "a:#{ var . size } :{"
36- if assoc and var . first . is_a? ( Array ) and var . first . size == 2
65+ if state . assoc and var . first . is_a? ( Array ) and var . first . size == 2
3766 var . each { |k , v |
38- s << PHP . serialize ( k , assoc ) << PHP . serialize ( v , assoc )
67+ s << PHP . do_serialize ( k , state ) << PHP . do_serialize ( v , state )
3968 }
4069 else
4170 var . each_with_index { |v , i |
42- s << "i:#{ i } ;#{ PHP . serialize ( v , assoc ) } "
71+ s << "i:#{ i } ;#{ PHP . do_serialize ( v , state ) } "
4372 }
4473 end
4574
@@ -48,15 +77,15 @@ def PHP.serialize(var, assoc = false) # {{{
4877 when Hash
4978 s << "a:#{ var . size } :{"
5079 var . each do |k , v |
51- s << "#{ PHP . serialize ( k , assoc ) } #{ PHP . serialize ( v , assoc ) } "
80+ s << "#{ PHP . do_serialize ( k , state ) } #{ PHP . do_serialize ( v , state ) } "
5281 end
5382 s << '}'
5483
5584 when Struct
5685 # encode as Object with same name
5786 s << "O:#{ var . class . to_s . bytesize } :\" #{ var . class . to_s . downcase } \" :#{ var . members . length } :{"
5887 var . members . each do |member |
59- s << "#{ PHP . serialize ( member , assoc ) } #{ PHP . serialize ( var [ member ] , assoc ) } "
88+ s << "#{ PHP . do_serialize ( member , state ) } #{ PHP . do_serialize ( var [ member ] , state ) } "
6089 end
6190 s << '}'
6291
@@ -81,7 +110,7 @@ def PHP.serialize(var, assoc = false) # {{{
81110 # encode as Object with same name
82111 s << "O:#{ var . class . to_s . bytesize } :\" #{ var . class . to_s . downcase } \" :#{ v . length } :{"
83112 v . each do |k , v |
84- s << "#{ PHP . serialize ( k . to_s , assoc ) } #{ PHP . serialize ( v , assoc ) } "
113+ s << "#{ PHP . do_serialize ( k . to_s , state ) } #{ PHP . do_serialize ( v , state ) } "
85114 end
86115 s << '}'
87116 else
@@ -164,19 +193,25 @@ def PHP.unserialize(string, classmap = nil, assoc = false) # {{{
164193
165194 ret = nil
166195 original_encoding = string . encoding
196+ state = SerializationState ::ToUnserialize . new . tap { |state |
197+ state . assoc = assoc
198+ state . classmap = classmap
199+ state . original_encoding = original_encoding
200+ }
201+
167202 string = StringIOReader . new ( string . force_encoding ( 'BINARY' ) )
168203 while string . string [ string . pos , 32 ] =~ /^(\w +)\| / # session_name|serialized_data
169204 ret ||= { }
170205 string . pos += $&. size
171- ret [ $1] = PHP . do_unserialize ( string , classmap , assoc , original_encoding )
206+ ret [ $1] = PHP . do_unserialize ( string , state )
172207 end
173208
174- ret || PHP . do_unserialize ( string , classmap , assoc , original_encoding )
209+ ret || PHP . do_unserialize ( string , state )
175210 end
176211
177212 private
178213
179- def PHP . do_unserialize ( string , classmap , assoc , original_encoding )
214+ def PHP . do_unserialize ( string , state )
180215 val = nil
181216 # determine a type
182217 type = string . read ( 2 ) [ 0 , 1 ]
@@ -185,7 +220,7 @@ def PHP.do_unserialize(string, classmap, assoc, original_encoding)
185220 count = string . read_until ( '{' ) . to_i
186221 val = Array . new
187222 count . times do |i |
188- val << [ do_unserialize ( string , classmap , assoc , original_encoding ) , do_unserialize ( string , classmap , assoc , original_encoding ) ]
223+ val << [ do_unserialize ( string , state ) , do_unserialize ( string , state ) ]
189224 end
190225 string . read ( 1 ) # skip the ending }
191226
@@ -203,13 +238,13 @@ def PHP.do_unserialize(string, classmap, assoc, original_encoding)
203238
204239 val = val . map { |tuple |
205240 tuple . map { |it |
206- it . kind_of? ( String ) ? it . force_encoding ( original_encoding ) : it
241+ it . kind_of? ( String ) ? it . force_encoding ( state . original_encoding ) : it
207242 }
208243 }
209244
210245 if array
211246 val . map! { |_ , value | value }
212- elsif !assoc
247+ elsif !state . assoc
213248 val = Hash [ val ]
214249 end
215250
@@ -223,21 +258,21 @@ def PHP.do_unserialize(string, classmap, assoc, original_encoding)
223258 len = string . read_until ( '{' ) . to_i
224259
225260 len . times do
226- attr = ( do_unserialize ( string , classmap , assoc , original_encoding ) )
227- attrs << [ attr . intern , ( attr << '=' ) . intern , do_unserialize ( string , classmap , assoc , original_encoding ) ]
261+ attr = ( do_unserialize ( string , state ) )
262+ attrs << [ attr . intern , ( attr << '=' ) . intern , do_unserialize ( string , state ) ]
228263 end
229264 string . read ( 1 )
230265
231266 val = nil
232267 # See if we need to map to a particular object
233- if classmap . has_key? ( klass )
234- val = classmap [ klass ] . new
268+ if state . classmap . has_key? ( klass )
269+ val = state . classmap [ klass ] . new
235270 elsif Struct . const_defined? ( klass ) # Nope; see if there's a Struct
236- classmap [ klass ] = val = Struct . const_get ( klass )
271+ state . classmap [ klass ] = val = Struct . const_get ( klass )
237272 val = val . new
238273 else # Nope; see if there's a Constant
239274 begin
240- classmap [ klass ] = val = Module . const_get ( klass )
275+ state . classmap [ klass ] = val = Module . const_get ( klass )
241276
242277 val = val . new
243278 rescue NameError # Nope; make a new Struct
@@ -252,7 +287,7 @@ def PHP.do_unserialize(string, classmap, assoc, original_encoding)
252287
253288 when 's' # string, s:length:"data";
254289 len = string . read_until ( ':' ) . to_i + 3 # quotes, separator
255- val = string . read ( len ) [ 1 ...-2 ] . force_encoding ( original_encoding ) # read it, kill useless quotes
290+ val = string . read ( len ) [ 1 ...-2 ] . force_encoding ( state . original_encoding ) # read it, kill useless quotes
256291
257292 when 'i' # integer, i:123
258293 val = string . read_until ( ';' ) . to_i
0 commit comments