最近一个项目里使用mysql数据库,维护单位要求字段平均长度必须小于1k,由于存的东西太多,有的达到了14k,所以必须要压缩
开始想的是对内容gzcompress后base64,但这会增加1/3的数据量,考虑到维护单位的变态要求,考虑对内容gzcompress后转成二进制流后直接存成varbinary,这样保存数据就不用考虑编码的问题了。
php转成二进制流使用的就是pack和unpack,使用如下:
/**
* 将字符串压缩并转成二进制流
* @param $string
* @return string
*/
public static function gzCompressAndToBinary($string) {
$cmpr = gzcompress($string);
return pack('A*', $cmpr);
}
/**
* 将二进制流解压成字符串
* 与gzCompressAndToBinary操作相反
* @param $bytes
* @return mixed
*/
public static function gzUncompressFromBinary($bytes) {
$unpacks = unpack('A*', $bytes);
$gzcomp = '';
foreach ($unpacks as $k => $v) {
if (!empty($v)) {
$gzcomp = $v;
break; // 测试发现值对应的索引是1,而不是0
}
}
return gzuncompress($gzcomp);
}
但后来发现gzuncompress会报错“gzuncompress(): data error”
在网上找了各种资料都没有正解,其中有一个人问了存在myISAM模式下没有问题,但保存在innodb模式下会出现解压失败的情况
没有仔细去研究myISAM和innodb的区别,但可以推测是在数据保存过程或数据取出过程中发生了微妙的变化,所以怀疑是在二进制转换时发生的变化,因为压缩和解压缩没有参数影响结果,而pack和unpack时有一个格式字符
查询php说明
Code | Description |
---|---|
a | NUL-padded string |
A | SPACE-padded string |
Code | Description |
---|---|
a | 以NUL字节填充字符串空白 |
A | 以SPACE(空格)填充字符串 |
$string = pack('a6', 'china');
var_dump($string); //输出结果: string(6) "china",最后一个字节是不可见的NUL
echo ord($string[5]); //输出结果: 0(ASCII码中0对应的就是nul)
//A同理
$string = pack('A6', 'china');
var_dump($string); //输出结果: string(6) "china ",最后一个字节是空格
echo ord($string[5]); //输出结果: 32(ASCII码中32对应的就是空格)
尝试一下使用unpack('a*', $string);来解二进制流,发现可以解之前不能解出来的信息
然后把生成和解二进制流的format都换成'a*',问题解决。