3

我一直试图弄清楚 Pack/Unpack 的 PHP 实现是否可以做一些 Perl 版本可以做的事情。我希望能够在 PHP 中执行的示例是:

http://perldoc.perl.org/perlpacktut.html#String-Lengths

# pack a message: ASCIIZ, ASCIIZ, length/string, byte
my $msg = pack( 'Z* Z* C/A* C', $src, $dst, $sm, $prio );
# unpack
( $src, $dst, $sm, $prio ) = unpack( 'Z* Z* C/A* C', $msg );

这个 Perl 代码的作用被描述为:

将两个包代码与斜杠 (/) 组合在一起,将它们与参数列表中的单个值相关联。在pack中,参数的长度是按照第一个代码来打包的,而参数本身是在斜杠后面用模板代码转换后添加的。

即,您可以打包可变长度的字符串,然后在一个步骤中解压缩它们,而不必先计算字符串的长度,然后将其作为单独的步骤提取。

PHP 手册没有提到此功能,任何尝试将“C/A*”之类的模式插入 unpack 都会给我带来错误。这是手册中的疏忽还是只是 PHP 版本不支持的内容?

4

1 回答 1

5

不幸的是,PHP 打包和解包函数不提供像 Perl 这样的变量(以空结尾)字符串的自动打包和解包。

为了适应此功能,请考虑将 unpack 函数包装到一个辅助类中,如下所示:

class Packer {
    static function unpack($mask, $data, &$pos) {
        try {
            $result = array();
            $pos = 0;
            foreach($mask as $field) {
                $subject = substr($data, $pos);
                $type = $field[0];
                $name = $field[1];
                switch($type) {
                    case 'N':
                    case 'n':
                    case 'C':
                    case 'c':
                        $temp = unpack("{$type}temp", $subject);
                        $result[$name] = $temp['temp'];
                        if($type=='N') {
                            $result[$name] = (int)$result[$name];
                        }

                        $pos += ($type=='N' ? 4 : ($type=='n' ? 2 : 1));
                        break;
                    case 'a':
                        $nullPos = strpos($subject, "\0") + 1;
                        $temp = unpack("a{$nullPos}temp", $subject);
                        $result[$name] = $temp['temp'];
                        $pos += $nullPos;
                        break;
                }
            }
            return $result;
        } catch(Exception $e) {
            $message = $e->getMessage();
            throw new Exception("unpack failed with error '{$message}'");
        }
    }
}

请注意,此函数并未实现所有解包类型,仅作为示例。

于 2012-07-24T14:36:11.993 回答