php_session 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +44 -3
- data/lib/php_session/decoder.rb +9 -8
- data/lib/php_session/encoder.rb +52 -34
- data/lib/php_session/version.rb +1 -1
- data/lib/php_session.rb +11 -3
- data/php_session.gemspec +1 -1
- data/spec/php_session/encoder_spec.rb +7 -0
- data/spec/php_session_spec.rb +60 -3
- data/spec/spec_helper.rb +15 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b17d2e471e2fc62c4c3681598183b9ce7551a277
|
4
|
+
data.tar.gz: 45400c08a847f2ef18c8e0241648542fa01bc1ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 890cec71b4f562a2ac591099a36ea7371c190403546fb216749a72dc7dfc883ff520d72b77d87295d097a446a93ad97a625457f9067954d8ccbd4efc4ae6e869
|
7
|
+
data.tar.gz: 608e598aabacdf55c0d1c834057ff1befe09ea8898e3438b9b3b4048a1a99eb76f10eb74072d401e8c4e73b301308a42bc39063443a7958a7eba3770d5f3c145
|
data/README.md
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# PHPSession
|
2
2
|
[](https://travis-ci.org/Shinpeim/ruby_php_session)
|
3
3
|
|
4
|
+
## Description
|
4
5
|
PHPSession is a php session file reader/writer. Multibyte string and exclusive control are supported.
|
5
6
|
|
6
7
|
When decoding php session data to ruby objects,
|
7
8
|
|
8
|
-
*
|
9
|
-
*
|
9
|
+
* Associative arrays in PHP is mapped to hashes in ruby.
|
10
|
+
* Objects in PHP is mapped to instances of Struct::ClassName in ruby.
|
10
11
|
|
11
12
|
When encoding ruby objects to php session data,
|
12
13
|
|
@@ -15,6 +16,35 @@ When encoding ruby objects to php session data,
|
|
15
16
|
* Arrays in ruby is mapped to a associative arrays which's keys are integer in PHP.
|
16
17
|
* Hashes in ruby is mapped to a associative arrays which's keys are string in PHP.
|
17
18
|
|
19
|
+
### Multibyte support
|
20
|
+
|
21
|
+
Passing option to PHPSession.new, you can handle encodings.
|
22
|
+
|
23
|
+
Options are:
|
24
|
+
|
25
|
+
* :internal_encoding
|
26
|
+
|
27
|
+
When this value is not nil, Session decoder tries to
|
28
|
+
encode string values into this encoding.
|
29
|
+
|
30
|
+
For a instance, if your php session file written in EUC-JP and you
|
31
|
+
like to handle string as UTF-8 in Ruby, you should set :internal_encoding
|
32
|
+
as "UTF-8" and :external_encoding as "EUC-JP".
|
33
|
+
|
34
|
+
Default value is Encoding.default_internal.
|
35
|
+
|
36
|
+
* :external_encoding
|
37
|
+
|
38
|
+
This value should be same as php session file's encoding.
|
39
|
+
Encoder tries to encode string values into this encoding.
|
40
|
+
|
41
|
+
Default value is Encoding.default_external.
|
42
|
+
|
43
|
+
* :encoding_option
|
44
|
+
|
45
|
+
This value is passed to String#encode.
|
46
|
+
|
47
|
+
|
18
48
|
## Installation
|
19
49
|
|
20
50
|
Add this line to your application's Gemfile:
|
@@ -31,11 +61,22 @@ Or install it yourself as:
|
|
31
61
|
|
32
62
|
## Usage
|
33
63
|
# initialize
|
34
|
-
|
64
|
+
option = {
|
65
|
+
:internal_encoding => "UTF-8", # value will be decoded as UTF-8
|
66
|
+
:external_encoding => "EUC-JP", # encoding of sesion file is EUC-JP
|
67
|
+
:encoding_option => {:undef => :replace} # passed to String#encode
|
68
|
+
}
|
69
|
+
# option's default values are
|
70
|
+
# :internal_encoding => Encoding.default_internal_encoding
|
71
|
+
# :external_encoding => Encoding.default_external_encoding
|
72
|
+
# :encoding_option => {}
|
73
|
+
session = PHPSession.new(session_file_dir, session_id, option)
|
35
74
|
|
36
75
|
begin
|
37
76
|
# load session data from file and obtain a lock
|
38
77
|
data = session.load
|
78
|
+
|
79
|
+
data.is_a? Hash # => true
|
39
80
|
|
40
81
|
# save session and release the lock
|
41
82
|
session.commit(data)
|
data/lib/php_session/decoder.rb
CHANGED
@@ -2,15 +2,16 @@
|
|
2
2
|
class PHPSession
|
3
3
|
class Decoder
|
4
4
|
attr_accessor :buffer, :state, :stack, :array
|
5
|
-
attr_reader :encoding
|
5
|
+
attr_reader :encoding, :encoding_option
|
6
6
|
|
7
|
-
def self.decode(string, encoding =
|
8
|
-
self.new(string, encoding).decode
|
7
|
+
def self.decode(string, encoding = nil, encoding_option = {})
|
8
|
+
self.new(string, encoding, encoding_option).decode
|
9
9
|
end
|
10
10
|
|
11
|
-
def initialize(string, encoding)
|
11
|
+
def initialize(string, encoding, encoding_option)
|
12
12
|
@encoding = encoding
|
13
|
-
@
|
13
|
+
@encoding_option = encoding_option
|
14
|
+
@buffer = string
|
14
15
|
@data = {}
|
15
16
|
@state = State::VarName
|
16
17
|
@stack = []
|
@@ -172,11 +173,11 @@ class PHPSession
|
|
172
173
|
length = decoder.stack.pop
|
173
174
|
length_include_quotes = length + 3
|
174
175
|
|
175
|
-
value_include_quotes = decoder.buffer
|
176
|
+
value_include_quotes = decoder.buffer.byteslice(0, length_include_quotes)
|
176
177
|
value = value_include_quotes.gsub(/^"/,'').gsub(/";$/, '')
|
177
|
-
value.force_encoding(decoder.encoding)
|
178
178
|
|
179
|
-
|
179
|
+
value = value.encode(decoder.encoding, decoder.encoding_option) if decoder.encoding
|
180
|
+
decoder.buffer = decoder.buffer.byteslice(length_include_quotes .. -1)
|
180
181
|
|
181
182
|
decoder.process_value(value)
|
182
183
|
end
|
data/lib/php_session/encoder.rb
CHANGED
@@ -1,88 +1,106 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
class PHPSession
|
3
3
|
class Encoder
|
4
|
-
|
4
|
+
attr_reader :encoding, :encoding_option
|
5
|
+
def self.encode(hash, encoding = nil, encoding_option = {})
|
6
|
+
encoding = Encoding.default_external if encoding.nil?
|
7
|
+
self.new(encoding, encoding_option).encode(hash)
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(encoding, encoding_option)
|
11
|
+
@encoding = encoding
|
12
|
+
@encoding_option = encoding_option
|
13
|
+
end
|
14
|
+
|
15
|
+
def encode(hash)
|
5
16
|
serialized = hash.map do|k,v|
|
6
|
-
"#{k}|#{serialize(v)}"
|
17
|
+
"#{k.to_s}|#{serialize(v)}"
|
7
18
|
end
|
8
19
|
serialized.join
|
9
20
|
end
|
10
21
|
|
11
|
-
|
12
|
-
|
13
|
-
def self.serialize(value)
|
22
|
+
def serialize(value)
|
14
23
|
get_serializer(value.class).serialize(value)
|
15
24
|
end
|
16
25
|
|
17
|
-
|
26
|
+
private
|
27
|
+
|
28
|
+
def get_serializer(klass)
|
18
29
|
case
|
19
30
|
when klass <= String || klass <= Symbol
|
20
|
-
StringSerializer
|
31
|
+
StringSerializer.new(self)
|
21
32
|
when klass <= Integer
|
22
|
-
IntegerSerializer
|
33
|
+
IntegerSerializer.new(self)
|
23
34
|
when klass <= Float
|
24
|
-
FloatSerializer
|
35
|
+
FloatSerializer.new(self)
|
25
36
|
when klass <= NilClass
|
26
|
-
NilSerializer
|
37
|
+
NilSerializer.new(self)
|
27
38
|
when klass <= TrueClass || klass <= FalseClass
|
28
|
-
BooleanSerializer
|
39
|
+
BooleanSerializer.new(self)
|
29
40
|
when klass <= Hash
|
30
|
-
HashSerializer
|
41
|
+
HashSerializer.new(self)
|
31
42
|
when klass <= Array
|
32
|
-
ArraySerializer
|
43
|
+
ArraySerializer.new(self)
|
33
44
|
when klass <= Struct
|
34
|
-
StructSerializer
|
45
|
+
StructSerializer.new(self)
|
35
46
|
else
|
36
47
|
raise Errors::EncodeError, "unsupported class:#{klass.to_s} is passed."
|
37
48
|
end
|
38
49
|
end
|
39
50
|
|
40
|
-
|
41
|
-
def
|
42
|
-
|
51
|
+
class Serializer
|
52
|
+
def initialize(encoder)
|
53
|
+
@encoder = encoder
|
54
|
+
end
|
55
|
+
end
|
56
|
+
class StringSerializer < Serializer
|
57
|
+
def serialize(value)
|
58
|
+
value = value.to_s
|
59
|
+
# encode here for valid bytesize
|
60
|
+
s = value.encode(@encoder.encoding, @encoder.encoding_option)
|
43
61
|
%|s:#{s.bytesize}:"#{s}";|
|
44
62
|
end
|
45
63
|
end
|
46
|
-
class IntegerSerializer
|
47
|
-
def
|
64
|
+
class IntegerSerializer < Serializer
|
65
|
+
def serialize(value)
|
48
66
|
%|i:#{value};|
|
49
67
|
end
|
50
68
|
end
|
51
|
-
class FloatSerializer
|
52
|
-
def
|
69
|
+
class FloatSerializer < Serializer
|
70
|
+
def serialize(value)
|
53
71
|
%|d:#{value};|
|
54
72
|
end
|
55
73
|
end
|
56
|
-
class NilSerializer
|
57
|
-
def
|
74
|
+
class NilSerializer < Serializer
|
75
|
+
def serialize(value)
|
58
76
|
%|N;|
|
59
77
|
end
|
60
78
|
end
|
61
|
-
class BooleanSerializer
|
62
|
-
def
|
79
|
+
class BooleanSerializer < Serializer
|
80
|
+
def serialize(value)
|
63
81
|
%|b:#{value ? 1 : 0};|
|
64
82
|
end
|
65
83
|
end
|
66
|
-
class HashSerializer
|
67
|
-
def
|
84
|
+
class HashSerializer < Serializer
|
85
|
+
def serialize(value)
|
68
86
|
serialized_values = value.map do |k, v|
|
69
|
-
[
|
87
|
+
[@encoder.serialize(k), @encoder.serialize(v)]
|
70
88
|
end
|
71
89
|
%|a:#{value.size}:{#{serialized_values.flatten.join}}|
|
72
90
|
end
|
73
91
|
end
|
74
|
-
class ArraySerializer
|
75
|
-
def
|
92
|
+
class ArraySerializer < Serializer
|
93
|
+
def serialize(value)
|
76
94
|
key_values = value.map.with_index{|el, i| [i, el]}
|
77
95
|
hash = Hash[key_values]
|
78
|
-
HashSerializer.serialize(hash)
|
96
|
+
HashSerializer.new(@encoder).serialize(hash)
|
79
97
|
end
|
80
98
|
end
|
81
|
-
class StructSerializer
|
82
|
-
def
|
99
|
+
class StructSerializer < Serializer
|
100
|
+
def serialize(value)
|
83
101
|
key_values = value.members.zip(value.values)
|
84
102
|
serialized_key_values = key_values.map do |kv|
|
85
|
-
kv.map {|el|
|
103
|
+
kv.map {|el| @encoder.serialize(el)}
|
86
104
|
end
|
87
105
|
class_name = value.class.to_s.gsub(/^Struct::/,'')
|
88
106
|
%|o:#{class_name.bytesize}:"#{class_name}":#{key_values.size}:{#{serialized_key_values.flatten.join}}|
|
data/lib/php_session/version.rb
CHANGED
data/lib/php_session.rb
CHANGED
@@ -6,7 +6,13 @@ require "php_session/encoder"
|
|
6
6
|
|
7
7
|
class PHPSession
|
8
8
|
attr_reader :data
|
9
|
-
def initialize(session_dir, session_id)
|
9
|
+
def initialize(session_dir, session_id, option = {})
|
10
|
+
default_option = {
|
11
|
+
:internal_encoding => Encoding.default_internal,
|
12
|
+
:external_encoding => Encoding.default_external,
|
13
|
+
:encoding_option => {},
|
14
|
+
}
|
15
|
+
@option = default_option.merge(option)
|
10
16
|
@session_dir = File.expand_path(session_dir)
|
11
17
|
set_session_id(session_id)
|
12
18
|
|
@@ -20,7 +26,9 @@ class PHPSession
|
|
20
26
|
raise PHPSession::Errors, "can't obtain lock of session file"
|
21
27
|
end
|
22
28
|
|
23
|
-
|
29
|
+
# set internal_encoding to nil to avoid encoding conversion
|
30
|
+
@file.set_encoding(@option[:external_encoding], nil)
|
31
|
+
data = Decoder.decode(@file.read, @option[:internal_encoding], @option[:encoding_option]) || {}
|
24
32
|
@file.rewind
|
25
33
|
data
|
26
34
|
end
|
@@ -37,7 +45,7 @@ class PHPSession
|
|
37
45
|
|
38
46
|
def commit(data)
|
39
47
|
@file.truncate(0)
|
40
|
-
@file.write(Encoder.encode(data))
|
48
|
+
@file.write(Encoder.encode(data, @option[:external_encoding], @option[:encoding_option]))
|
41
49
|
ensure_file_closed
|
42
50
|
end
|
43
51
|
|
data/php_session.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Shinpei Maruyama"]
|
10
10
|
spec.email = ["shinpeim@gmail.com"]
|
11
11
|
spec.description = %q{php session reader/writer}
|
12
|
-
spec.summary = %q{php_session is a php session file reader/writer. Multibyte string and
|
12
|
+
spec.summary = %q{php_session is a php session file reader/writer. Multibyte string and exclusive control is supported}
|
13
13
|
spec.homepage = "https://github.com/Shinpeim/ruby_php_session"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
@@ -17,6 +17,13 @@ describe PHPSession::Encoder do
|
|
17
17
|
).to eq('hoge|s:9:"テスト";')
|
18
18
|
end
|
19
19
|
end
|
20
|
+
context "when given multi string value with external encoding" do
|
21
|
+
it "should return 'KEY|SERIALIZED_STRING'" do
|
22
|
+
expect(
|
23
|
+
PHPSession::Encoder.encode({:hoge => "テスト🍣"}, "EUC-JP", {:undef => :replace})
|
24
|
+
).to eq('hoge|s:7:"テスト?";'.encode('EUC-JP'))
|
25
|
+
end
|
26
|
+
end
|
20
27
|
context "when given int value" do
|
21
28
|
it "should return 'KEY|SERIALIZED_INT" do
|
22
29
|
expect(
|
data/spec/php_session_spec.rb
CHANGED
@@ -3,6 +3,56 @@ require 'spec_helper'
|
|
3
3
|
|
4
4
|
describe PHPSession do
|
5
5
|
describe "load" do
|
6
|
+
context "when session file encoding is utf8" do
|
7
|
+
before do
|
8
|
+
@session_file = create_dummy_session_file('key|s:13:"テスト🍺";')
|
9
|
+
end
|
10
|
+
it "should be able to load file with internal:nil, external:utf8" do
|
11
|
+
option = {
|
12
|
+
:internal_encoding => nil,
|
13
|
+
:external_encoding => "UTF-8",
|
14
|
+
}
|
15
|
+
session = PHPSession.new(@session_file[:dir_name], @session_file[:session_id], option)
|
16
|
+
begin
|
17
|
+
data = session.load
|
18
|
+
expect(data).to eq({"key" => "テスト🍺"})
|
19
|
+
ensure
|
20
|
+
session.ensure_file_closed
|
21
|
+
end
|
22
|
+
end
|
23
|
+
it "should be able to load file with internal:utf8, external:utf8" do
|
24
|
+
option = {
|
25
|
+
:internal_encoding => "UTF-8",
|
26
|
+
:external_encoding => "UTF-8",
|
27
|
+
}
|
28
|
+
session = PHPSession.new(@session_file[:dir_name], @session_file[:session_id], option)
|
29
|
+
begin
|
30
|
+
data = session.load
|
31
|
+
expect(data).to eq({"key" => "テスト🍺"})
|
32
|
+
ensure
|
33
|
+
session.ensure_file_closed
|
34
|
+
end
|
35
|
+
end
|
36
|
+
it "should return euc-jp string with internal:euc-jp, exterenal:utf8" do
|
37
|
+
option = {
|
38
|
+
:internal_encoding => "EUC-JP",
|
39
|
+
:external_encoding => "UTF-8",
|
40
|
+
:encoding_option => {
|
41
|
+
:undef => :replace
|
42
|
+
}
|
43
|
+
}
|
44
|
+
session = PHPSession.new(@session_file[:dir_name], @session_file[:session_id], option)
|
45
|
+
begin
|
46
|
+
data = session.load
|
47
|
+
expect(data).to eq({"key" => "テスト🍺".encode("EUC-JP", {:undef => :replace})})
|
48
|
+
ensure
|
49
|
+
session.ensure_file_closed
|
50
|
+
end
|
51
|
+
end
|
52
|
+
after do
|
53
|
+
File.delete(@session_file[:file_path])
|
54
|
+
end
|
55
|
+
end
|
6
56
|
context "when session file exists" do
|
7
57
|
before do
|
8
58
|
@session_file = create_dummy_session_file('key|s:1:"a";')
|
@@ -42,12 +92,19 @@ describe PHPSession do
|
|
42
92
|
end
|
43
93
|
|
44
94
|
it "should save session_data in session_file" do
|
45
|
-
|
95
|
+
option = {
|
96
|
+
:external_encoding => "EUC-JP",
|
97
|
+
:internal_encoding => "UTF-8",
|
98
|
+
:encoding_option => {:undef => :replace}
|
99
|
+
}
|
100
|
+
session = PHPSession.new(@session_file[:dir_name], @session_file[:session_id], option)
|
46
101
|
data = session.load
|
47
|
-
data["key"] = "
|
102
|
+
data["key"] = "テスト🍣"
|
48
103
|
session.commit(data)
|
49
104
|
|
50
|
-
|
105
|
+
# read in bytesequence mode to avoid encoding conversion
|
106
|
+
byte_sequence = IO.read(@session_file[:file_path], File.size(@session_file[:file_path]))
|
107
|
+
expect(byte_sequence.force_encoding('EUC-JP')).to eq('key|s:7:"テスト?";'.encode("EUC-JP"))
|
51
108
|
end
|
52
109
|
|
53
110
|
after do
|
data/spec/spec_helper.rb
CHANGED
@@ -12,3 +12,18 @@ def create_dummy_session_file(text)
|
|
12
12
|
|
13
13
|
{:file_path => file_path, :dir_name => dirname, :session_id => session_id}
|
14
14
|
end
|
15
|
+
|
16
|
+
def with_encoding(internal, external)
|
17
|
+
default_internal_was = Encoding.default_internal
|
18
|
+
default_external_was = Encoding.default_external
|
19
|
+
|
20
|
+
Encoding.default_external = external
|
21
|
+
Encoding.default_internal = internal
|
22
|
+
|
23
|
+
begin
|
24
|
+
yield
|
25
|
+
ensure
|
26
|
+
Encoding.default_external = default_external_was
|
27
|
+
Encoding.default_internal = default_internal_was
|
28
|
+
end
|
29
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: php_session
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shinpei Maruyama
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-10-
|
11
|
+
date: 2013-10-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -99,7 +99,7 @@ rubyforge_project:
|
|
99
99
|
rubygems_version: 2.0.0
|
100
100
|
signing_key:
|
101
101
|
specification_version: 4
|
102
|
-
summary: php_session is a php session file reader/writer. Multibyte string and
|
102
|
+
summary: php_session is a php session file reader/writer. Multibyte string and exclusive
|
103
103
|
control is supported
|
104
104
|
test_files:
|
105
105
|
- spec/php_session/decoder_spec.rb
|