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 コードが行うことは、次のように説明されています。

2 つの pack コードをスラッシュ (/) で結合すると、それらが引数リストの 1 つの値に関連付けられます。パックでは、引数の長さが取得され、最初のコードに従ってパックされますが、引数自体は、スラッシュの後のテンプレート コードで変換された後に追加されます。

つまり、最初に文字列の長さを把握してから別の手順として抽出するのではなく、可変長文字列をパックしてから 1 つの手順でアンパックできます。

PHP のマニュアルではこの機能について言及されておらず、'C/A*' のようなパターンを unpack に挿入しようとすると、エラーが発生します。それはマニュアルの見落としですか、それとも PHP バージョンがサポートしていないだけですか?

4

1 に答える 1

5

PHPのpackおよびunpack関数は、残念ながら、Perlのような変数(nullで終了する)文字列の自動パックおよびアンパックを提供しません。

この機能に対応するには、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 に答える