Discuz!官方免费开源建站系统

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索

建议新版Discuz对于数组设置项(setting)使用json格式替换serialize序列化

[复制链接]
mark35 发表于 2012-10-25 16:43:08 | 显示全部楼层 |阅读模式
本帖最后由 mark35 于 2012-12-3 19:25 编辑

因为在个人空间列表中被隐藏,故此存档 http://xiaozhong.biz/thread-287-1-1.html

Discuz系列对于设置项中数据类型(比如版块设置)采用序列化方式(serialize)保存,读取时使用unserialize()反序列化字符串为数组
序列化这种方式有个致命的缺点:字符集会影响序列化结果
对于这个数组序列化

  1. $s = [1, '小众站长网', 'http://www.xiaozhong.biz'];
  2. echo serialize($s);
复制代码
UTF-8环境下结果为
a:3:{i:0;i:1;i:1;s:15:"小众站长网";i:2;s:24:"http://www.xiaozhong.biz";}

GB2312环境下结果为
a:3:{i:0;i:1;i:1;s:10:"小众站长网";i:2;s:24:"http://www.xiaozhong.biz";}

注意看 “小众站长网”前面的数字,UTF-8下面为15,GB下面为10. 这是因为在UTF-8字符集中中文字长3-4个字节,而在GB/GBK中中日韩问字长都固定为2个字节。至于英文在两种字符集中都占1字节所以序列化长度是固定的

如此不同的序列化结果产生的兼容性在于不同字符集的discuz版本的数据库中保存的设置项目值是不相同的——在进行字符集版本转移时无法直接导出数据库为目的版本字符集然后再导入。必须对数组类型的设置项进行单独反序列化再使用iconv函数进行字符集转换然后才能序列化入库。遇上数组中还嵌套有数组就更加麻烦了。而如果数组中保存有已经序列化后字符串,那么此数组序列化后就……想着就头大……

故建议新版DZ程序在处理数组字符串化时使用json格式替代serialize序列化入库

  1. $s = [1, '小众网', 'http://xiaozhong.biz'];
复制代码
其结果分别为

  1. var_dump(json_encode($s));
  2. // string(49) "[1,"\u5c0f\u4f17\u7f51","http:\/\/xiaozhong.biz"]"

  3. var_dump(json_encode($s, JSON_UNESCAPED_UNICODE));
  4. // string(40) "[1,"小众网","http:\/\/xiaozhong.biz"]"

  5. var_dump(json_encode($s, JSON_UNESCAPED_SLASHES));
  6. // string(47) "[1,"\u5c0f\u4f17\u7f51","http://xiaozhong.biz"]"

  7. var_dump(json_encode($s, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
  8. // string(38) "[1,"小众网","http://xiaozhong.biz"]"

  9. PHP5.4.0         options 参数增加常量: JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, 和 JSON_UNESCAPED_UNICODE。
  10. PHP5.3.3         options 参数增加常量:JSON_NUMERIC_CHECK。
复制代码
虽然在不同参数下json_encode()的结果会不同,但无论哪种json_encode结果作为json_decode()的输入其解码的结果却是唯一的

  1. array (
  2.   0 => 1,
  3.   1 => '小众网',
  4.   2 => 'http://xiaozhong.biz',
  5. )
复制代码
如此非常方便对数据进行各种处理,比如迁移、升级、转换字符集

虽然在速度上json_encode/json_decode要比serialize/unserialize慢一些,但dz的缓存机制使得这种性能差别微乎其微——因为缓存中保存的数据都是解码后数组而不是需要反序列化的字符串



sw08 发表于 2012-10-27 16:30:53 | 显示全部楼层
字节数的问题,以前我做开发也经常碰到。
不过我更喜欢用implode来处理简单数组。

这个如果不是经常换编码的环境,一般也无所谓吧。
回复

使用道具 举报

 楼主| mark35 发表于 2012-10-27 18:07:51 | 显示全部楼层
本帖最后由 mark35 于 2012-12-3 19:26 编辑
sw08 发表于 2012-10-27 16:30
字节数的问题,以前我做开发也经常碰到。
不过我更喜欢用implode来处理简单数组。

implode()是个办法,不过逻辑上是对同一类别的数据进行处理,比如 pids数组包含待处理的pid值,这些值逻辑上是一类,并且是平等无次级划分。而setting设置项是多个不同类别、属性、层级的对象,这时就无法从程序上以及逻辑上进行简单字面量化。此时serialize(), json_encode()就是对此类包含复合体的数组进行字面量化的手段。如果不考虑多字节/字符集,那么serialize是很适合的。另外对于前端来说字符对象好像没有对应的原生unserialize反序列化方法,这就不适合ajax传输信息。而json序列化的字面量无论是老的不安全的eval()还是现在的JSON.parse()都可以轻松在客户端转换会标准json对象(可算是数组)。

对于编码问题,不一定是要在换编码(比如转换论坛程序)时才会遇到。可能在维护数据时因为调试机器自身编码与数据库编码不一致(比如linux系统文件系统默认是UTF-8,而你用的论坛是GBK)而需要耗费无关精力去解决编码问题

ps, dz开发人员很喜欢用implode展开后的结果字符串而不是数组作为实参。这点我在修改dz72是改不胜改。希望以后dz开发人员能规范一点,也方便日后维护以及他人的二次开发。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|Discuz! 官方站 ( 皖ICP备16010102号 )star

GMT+8, 2024-11-16 13:02 , Processed in 0.055058 second(s), 3 queries , Gzip On, Redis On.

Powered by Discuz! X3.4

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表