问题
I've been trying to figure out if the PHP implementation of Pack/Unpack can do something that the Perl version is able to do. The example I'd like to be able to do in PHP is:
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 );
What this Perl code does is described as:
Combining two pack codes with a slash (/) associates them with a single value from the argument list. In pack, the length of the argument is taken and packed according to the first code while the argument itself is added after being converted with the template code after the slash.
i.e. you can pack variable length strings and then unpack them in one step, rather than having to figure out the length of the string first and then extracting it as a separate step.
The PHP manual doesn't mention this capability and any attempt to insert a pattern like 'C/A*' into unpack is giving errors for me. Is that an oversight in the manual or just something that the PHP version doesn't support?
回答1:
PHP pack and unpack functions unfortunately do not provide automatic packing and unpacking of variable (null terminated) strings like Perl.
To accommodate for this functionality, consider wrapping the unpack function into a helper class like this:
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}'");
}
}
}
Please note that this function does not implement all unpack types and merely serves as an example.
来源:https://stackoverflow.com/questions/11632773/php-pack-unpack-can-it-handle-variable-length-strings