1个不稳定版本
0.6.0 | 2021年8月20日 |
---|
#1382 in 编码
7,578 每月下载量
63KB
1.5K SLoC
为serde提供PHP序列化支持
允许对PHP的 serialize()
/unserialize()
格式进行序列化和反序列化。有关详细信息,请参阅文档:docs.rs/php_serde.
lib.rs
:
为serde提供PHP序列化格式支持
PHP通过其 serialize()
和 unserialize()
方法使用自定义序列化格式。这个crate使用 serde
添加了对该格式的部分支持。
该格式的概述可以在 https://stackoverflow.com/questions/14297926/structure-of-a-serialized-php-string 中看到,详细信息请见 http://www.phpinternalsbook.com/php5/classes_objects/serialization.html。
支持什么?
-
基本和复合类型
PHP类型 Rust类型 布尔值 bool
整数 i64
(自动转换为其他类型支持)浮点数 f64
(自动转换为f32
支持)字符串 Vec<u8>
(PHP字符串不是UTF8)空值 解码为 None
数组(非关联数组) 元组结构体或 Vec<_>
数组(关联数组) 常规 结构体
或HashMap<_, _>
-
Rust
String
会自动转换为 PHP 字节数组。
无序数组
PHP 数组可以“无序”创建,因为它们将每个数组索引存储为显式的整数。因此以下代码
$arr = array();
$arr[0] = "zero";
$arr[3] = "three";
$arr[2] = "two";
$arr[1] = "one";
会生成一个等价于 ["zero", "one", "two", "three"] 的数组,至少在迭代时是这样。
因为反序列化不缓冲值,所以这些数组不能直接序列化为 Vec
。相反,它们应该被反序列化为映射,然后可以(如果需要的话)将其转换为 Vec
。
第二个问题是数组中的“空隙”,例如如果缺少键 1
的条目。如何填充这些通常取决于用户。
辅助函数 deserialize_unordered_array
可以与 serde 的 deserialize_with
装饰器一起使用,以自动缓冲和排序,同时通过关闭任何间隙来填充空隙。
缺少什么?
- PHP 对象
- 非字符串/数字数组键,除非在反序列化为
HashMap
时 - 混合数组。假设数组键始终具有相同的键类型(注意:如果需要,请考虑通过扩展此库来使用变体类型)。
示例使用
给定一个示例数据结构,使用以下 PHP 代码存储会话令牌
<?php
$serialized = serialize(array("user", "", array()));
echo($serialized);
因此以下输出
a:3:{i:0;s:4:"user";i:1;s:0:"";i:2;a:0:{}}
,可以使用以下 rust 代码重新构造数据
use serde::Deserialize;
use php_serde::from_bytes;
#[derive(Debug, Deserialize, Eq, PartialEq)]
struct Data(Vec<u8>, Vec<u8>, SubData);
#[derive(Debug, Deserialize, Eq, PartialEq)]
struct SubData();
let input = br#"a:3:{i:0;s:4:"user";i:1;s:0:"";i:2;a:0:{}}"#;
assert_eq!(
from_bytes::<Data>(input).unwrap(),
Data(b"user".to_vec(), b"".to_vec(), SubData())
);
同样,如果 PHP 数组使用键,则也支持结构体
<?php
$serialized = serialize(
array("foo" => true,
"bar" => "xyz",
"sub" => array("x" => 42))
);
echo($serialized);
在 Rust 中
#[derive(Debug, Deserialize, Eq, PartialEq)]
struct Outer {
foo: bool,
bar: String,
sub: Inner,
}
#[derive(Debug, Deserialize, Eq, PartialEq)]
struct Inner {
x: i64,
}
let input = br#"a:3:{s:3:"foo";b:1;s:3:"bar";s:3:"xyz";s:3:"sub";a:1:{s:1:"x";i:42;}}"#;
let expected = Outer {
foo: true,
bar: "xyz".to_owned(),
sub: Inner { x: 42 },
};
let deserialized: Outer = from_bytes(input).expect("deserialization failed");
assert_eq!(deserialized, expected);
可选值
缺失的值可以设置为可选,如下例所示
<?php
$location_a = array();
$location_b = array("province" => "Newfoundland and Labrador, CA");
$location_c = array("postalcode" => "90002",
"country" => "United States of America");
echo(serialize($location_a) . "\n");
echo(serialize($location_b) . "\n");
# -> a:1:{s:8:"province";s:29:"Newfoundland and Labrador, CA";}
echo(serialize($location_c) . "\n");
# -> a:2:{s:10:"postalcode";s:5:"90002";s:7:"country";
# s:24:"United States of America";}
以下对 Location
的声明将能够解析所有三个示例输入。
#[derive(Debug, Deserialize, Eq, PartialEq)]
struct Location {
province: Option<String>,
postalcode: Option<String>,
country: Option<String>,
}
完整往返示例
use serde::{Deserialize, Serialize};
use php_serde::{to_vec, from_bytes};
#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
struct UserProfile {
id: u32,
name: String,
tags: Vec<String>,
}
let orig = UserProfile {
id: 42,
name: "Bob".to_owned(),
tags: vec!["foo".to_owned(), "bar".to_owned()],
};
let serialized = to_vec(&orig).expect("serialization failed");
let expected = br#"a:3:{s:2:"id";i:42;s:4:"name";s:3:"Bob";s:4:"tags";a:2:{i:0;s:3:"foo";i:1;s:3:"bar";}}"#;
assert_eq!(serialized, &expected[..]);
let profile: UserProfile = from_bytes(&serialized).expect("deserialization failed");
assert_eq!(profile, orig);
依赖关系
~200–490KB
~11K SLoC