跳转到主要内容

将php的serialize和unserialize函数移植到python。

项目描述

将php的serializeunserialize函数移植到python。此模块实现了python序列化接口(例如:提供dumpsloads等类似函数)。

用法

>>> from phpserialize import *
>>> obj = dumps("Hello World")
>>> loads(obj)
'Hello World'

由于PHP不知道列表的概念,列表在PHP中以哈希表的形式进行序列化。实际上,序列化列表的反向值是一个字典。

>>> loads(dumps(range(2)))
{0: 0, 1: 1}

如果您想再次获得一个列表,可以使用dict_to_list辅助函数。

>>> dict_to_list(loads(dumps(range(2))))
[0, 1]

您还可以使用dict_to_tuple函数将其转换为元组。

>>> dict_to_tuple(loads(dumps((1, 2, 3))))
(1, 2, 3)

另一个问题是Unicode字符串。默认情况下,Unicode字符串被编码为‘utf-8’,但在unserialize时不会被解码。这是因为phpserialize无法猜测字符串中是否包含二进制或文本数据。

>>> loads(dumps(u'Hello W\xf6rld'))
'Hello W\xc3\xb6rld'

如果您知道结果中只有已知字符集的文本数据,可以在调用loads时将decode_strings设置为True来解码字符串。

>>> loads(dumps(u'Hello W\xf6rld'), decode_strings=True)
u'Hello W\xf6rld'

字典键限于字符串和整数。 None 转换为空字符串,浮点数和布尔值转换为整数以兼容PHP。

>>> loads(dumps({None: 14, 42.23: 'foo', True: [1, 2, 3]}))
{'': 14, 1: {0: 1, 1: 2, 2: 3}, 42: 'foo'}

它还提供了从文件对象读取的功能

>>> from StringIO import StringIO
>>> stream = StringIO('a:2:{i:0;i:1;i:1;i:2;}')
>>> dict_to_list(load(stream))
[1, 2]

以及写入这些对象

>>> stream = StringIO()
>>> dump([1, 2], stream)
>>> stream.getvalue()
'a:2:{i:0;i:1;i:1;i:2;}'

pickle一样支持对象链接

>>> stream = StringIO()
>>> dump([1, 2], stream)
>>> dump("foo", stream)
>>> stream.seek(0)
>>> load(stream)
{0: 1, 1: 2}
>>> load(stream)
'foo'

然而,此功能在PHP中不受支持。PHP将只反序列化第一个对象。

数组序列化

从1.2版本开始,您可以为反序列化函数提供一个数组钩子,该钩子通过一对列表调用函数以返回实际的数组对象。默认情况下,使用dict作为数组对象,这意味着关联数组会丢失顺序信息。

例如,您可以将有序字典传递给反序列化函数

>>> from collections import OrderedDict
>>> loads('a:2:{s:3:"foo";i:1;s:3:"bar";i:2;}',
...       array_hook=OrderedDict)
collections.OrderedDict([('foo', 1), ('bar', 2)])

对象序列化

PHP支持对象的序列化。从phpserialize的1.2版本开始,可以同时进行对象的序列化和反序列化。因为PHP和Python中的类名通常不对应,所以有一个单独的object_hook参数,用于创建这些类。

对于简单的测试示例,可以使用phpserialize.phpobject类。

>>> data = 'O:7:"WP_User":1:{s:8:"username";s:5:"admin";}'
>>> user = loads(data, object_hook=phpobject)
>>> user.username
'admin'
>>> user.__name__
'WP_User'

对象钩子是一个函数,它接受类名和包含实例数据的字典作为参数。实例数据键采用PHP格式,这通常不是您想要的。要将它转换为Python标识符,可以使用convert_member_dict函数。有关更多信息,请参阅下一节。以下是一个简单的对象钩子示例。

>>> class User(object):
...     def __init__(self, username):
...         self.username = username
...
>>> def object_hook(name, d):
...     cls = {'WP_User': User}[name]
...     return cls(**d)
...
>>> user = loads(data, object_hook=object_hook)
>>> user.username
'admin'

要序列化对象,可以使用dump函数的object_hook并返回phpobject的实例。

>>> def object_hook(obj):
...     if isinstance(obj, User):
...         return phpobject('WP_User', {'username': obj.username})
...     raise LookupError('unknown object')
...
>>> dumps(user, object_hook=object_hook)
'O:7:"WP_User":1:{s:8:"username";s:5:"admin";}'

PHP的对象系统

PHP对象系统源自编译语言,如Java和C#。可以通过将其设置为protectedprivate来保护属性,以防止外部访问。这不仅服务于封装内部结构的目的,还可以避免名称冲突。

在PHP中,继承链中的每个类都可以有一个具有相同名称的私有变量,而不会引起冲突。(这与Python的__var名称混淆系统类似)。

这个PHP类

class WP_UserBase {
    protected $username;

    public function __construct($username) {
        $this->username = $username;
    }
}

class WP_User extends WP_UserBase {
    private $password;
    public $flag;

    public function __construct($username, $password) {
        parent::__construct($username);
        $this->password = $password;
        $this->flag = 0;
    }
}

使用如下成员数据字典进行序列化

>>> data = {
...     ' * username':          'the username',
...     ' WP_User password':    'the password',
...     'flag':                 'the flag'
... }

因为这种访问系统在Python中不存在,convert_member_dict可以转换这个字典

>>> d = convert_member_dict(data)
>>> d['username']
'the username'
>>> d['password']
'the password'

phpobject类会即时执行这种转换。序列化的是类的特殊__php_vars__字典

>>> user = phpobject('WP_User', data)
>>> user.username
'the username'
>>> user.username = 'admin'
>>> user.__php_vars__[' * username']
'admin'

如你所见,在php对象上重新分配属性将尝试更改具有相同名称的私有或受保护的属性。设置一个未知属性将创建一个新的公共属性

>>> user.is_admin = True
>>> user.__php_vars__['is_admin']
True

要将phpobject转换为字典,可以使用_asdict方法

>>> d = user._asdict()
>>> d['username']
'admin'

Python 3 注意事项

由于Python 3中对Unicode的支持不再透明地处理字节和Unicode对象,我们不得不改变解码的方式。在Python 3中,你很可能希望始终解码字符串。因为这会在二进制数据上完全失败,phpserialize使用“surrogateescape”方法来避免在无效数据上失败。有关更多信息,请参阅Python 3的文档。

更改日志

1.3
  • 增加了对Python 3的支持

1.2
  • 增加了对对象序列化的支持

  • 增加了对数组钩子的支持

1.1
  • 增加了dict_to_listdict_to_tuple

  • 增加了对Unicode的支持

  • 允许对象链如pickle那样使用

项目详情


下载文件

下载适合您平台的自定义文件。如果您不确定选择哪个,请了解更多关于安装包的信息。

源分布

phpserialize-1.3.tar.gz (7.5 KB 查看散列)

上传时间

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面