百科狗-知识改变命运!
--

unpack() - php 选项信息函数

是丫丫呀1年前 (2023-11-21)阅读数 19#技术干货
文章标签例程

unpack()

(PHP 4, PHP 5, PHP 7)

Unpack data from binary string

说明

unpack(string $format,string $data[,int $offset= 0]): array

Unpacks from a binary string into an array according to the given$format.

The unpacked data is stored in an associative array. To accomplish this you have to name the different format codes and separate them by a slash /. If a repeater argument is present, then each of the array keys will have a sequence number behind the given name.

参数

$format

Seepack()for an explanation of the format codes.

$data

The packed data.

$offset

The offset to begin unpacking from.

返回值

Returns an associative array containing unpacked elements of binary string.

更新日志

版本说明
7.2.0floatanddoubletypes supports both Big Endian and Little Endian.
7.1.0The optional$offsethas been added.
5.5.0

Changes were made to bring this function into line with Perl:

The "a" code now retains trailing NULL bytes.

The "A" code now strips all trailing ASCII whitespace (spaces, tabs, newlines, carriage returns, and NULL bytes).

The "Z" code was added for NULL-padded strings, and removes trailing NULL bytes.

范例

Example #1unpack()example

以上例程会输出:

Array
(
    [chars] => 4
    [int] => 160
)

Example #2unpack()example with a repeater

以上例程会输出:

Array
(
    [chars1] => 4
    [chars2] => 0
    [int] => 40960
)

注释

Caution

Note that PHP internally stores integral values as signed. If you unpack a large unsigned long and it is of the same size as PHP internally stored values the result will be a negative number even though unsigned unpacking was specified.

Caution

If you do not name an element, numeric indices starting from1are used. Be aware that if you have more than one unnamed element, some data is overwritten because the numbering restarts from1for each element.

Example #3unpack()example with unnamed keys

以上例程会输出:

array(2) {
  [1]=>
  int(160)
  [2]=>
  int(66)
}

unpack() - php 选项信息函数

Note that the first value from thecspecifier is overwritten by the first value from thenspecifier.

参见

  • pack() 将数据打包成二进制字符串
A helper class to convert integer to binary strings and vice versa. Useful for writing and reading integers to / from files or sockets.

Usage example: 
I had a situation where I had to unpack a file filled with little-endian order double-floats in a way that would work on either little-endian or big-endian machines. PHP doesn't have a formatting code that will change the byte order of doubles, so I wrote this workaround.

This outputs:
$array[chars1] = 65 
$array[chars2] = 65 
$array[int] = 65 
Here, we assume that the ascii code for character 'A' is decimal 65.
Remebering that the format string structure is:
 [] [] [/ ...],
in this example, the format string instructs the function to
 1. ("c2...") Read two chars from the second argument ("AA ...), 
 2. (...chars...) Use the array-keys "chars1", and "chars2" for 
   these two chars read,
 3. (.../n...) Read a short int from the second argument (...\0A"),
 4. (...int") Use the word "int" as the array key for the just read
   short.
I hope this is clearer now,
Sergio.
If having a zero-based index is useful/necessary, then instead of:
$int_list = unpack("s*", $some_binary_data);
 try:
$int_list = array_merge(unpack("s*", $some_binary_data));
This will return a 0-based array:
$int_list[0] = x
$int_list[1] = y
$int_list[2] = z
...
rather than the default 1-based array returned from unpack when no key is supplied:
$int_list[1] = x
$int_list[2] = y
$int_list[3] = z
...
It's not used often, but array_merge() with only one parameter will compress a sequentially-ordered numeric-index, starting with an index of [0].
Suppose we need to get some kind of internal representation of an integer, say 65, as a four-byte long. Then we use, something like:

The output is:
X-Powered-By: PHP/4.1.2
Content-type: text/html
4
***A*** 
(That is the string "A\0\0\0")
Now we want to go back from string "A\0\0\0" to number 65. In this case we can use:

And this outpus:
X-Powered-By: PHP/4.1.2
Content-type: text/html
$arr[] = 65
Let's give the array key a name, say "mykey". In this case, we can use: 

An this outpus:
X-Powered-By: PHP/4.1.2
Content-type: text/html
$arr[mykey] = 65
The "unpack" documentation is a little bit confusing. I think a more complete example could be:

whose output is:
X-Powered-By: PHP/4.1.2
Content-type: text/html
$array[chars1] = 65 
$array[chars2] = 65
$array[int] = 65
Note that the format string is something like [] [] [/ ...] I hope this clarifies something Sergio
be aware of the behavior of your system that PHP resides on.
On x86, unpack MAY not yield the result you expect for UInt32
This is due to the internal nature of PHP, being that integers are internally stored as SIGNED!
For x86 systems, unpack('N', "\xff\xff\xff\xff") results in -1
For (most?) x64 systems, unpack('N', "\xff\xff\xff\xff") results in 4294967295.
This can be verified by checking the value of PHP_INT_SIZE.
If this value is 4, you have a PHP that internally stores 32-bit.
A value of 8 internally stores 64-bit.
To work around this 'problem', you can use the following code to avoid problems with unpack.
The code is for big endian order but can easily be adjusted for little endian order (also, similar code works for 64-bit integers):

Do note that you *could* also use sprintf('%u', $x) to show the unsigned real value.
Also note that (at least when PHP_INT_SIZE = 4) the result WILL be a float value when the input is larger then 0x7fffffff (just check with gettype);
Hope this helps people.
The documentation is clear that an integer read using an unsigned format character will still be stored as a signed integer. The often-cited work-around is to use sprintf('%u', $bigint) to properly display integers with the MSB set.
In the case where the numeric value is more important than how it's displayed, you can still work with other large integers using intval() to "upgrade" your existing unsigned integers.
I had a problem comparing 32-bit integers read from files with hard-coded constants (file signatures tend to need this). Here's what I did to avoid converting everything into strings:

It works, but it's a little backwards. If anyone has any ideas on how to "downgrade" a signed integer into an unsigned integer without using strings, that would be a valuable note to add to the documentation.
Another option for converting binary data into PHP data types, is to use the Zend Framework's Zend_Io_Reader class:
http://bit.ly/9zAhgz
There's also a Zend_Io_Writer class that does the reverse.
Reading a text cell from an Excel spreadsheet returned a string with low-order embedded nulls: 0x4100 0x4200 etc. To remove the nulls, used

(unpack() didn't seem to help much here; needed chars back to re-constitute the string, not integers.)
If no key name is given [e.g., unpack('C*',$data)], the keys are simply integers starting at 1, and you have a standard array. (I know of no way to get the array to start at zero.)
If you use multiple types, you must give a key name for all of them (except optionally one), because the key counter is reset with each slash. For example, in unpack('n2/C*',$data), indices 1 and 2 of the returned array are filled by integers ('n'), then overwritten with characters ('C').
As stated above, "if you unpack a large unsigned long and it is of the same size as PHP internally stored values the result will be a negative number even though unsigned unpacking was specified."
To restore the original unsigned value, you could do this :
if ($unpackedVal 
If you just want to extract a dword/long int from a binary string, the following code works beautifully (intel endian):
$Number = ord($Buffer{0}) | (ord($Buffer{1})
Note that it takes even more time if you use a custom function to implement the implode+unpack+substr functions.
Now... This method uses the FREAD function:

I recommend using the FREAD method instead of SUBSTR.
Another test!!! This method is 10x faster than the above. This does not use the FOR loop:

If you want to read files much faster, you should try to reduce the number of loops and use the unpack function to its simplest and robust method.
The script following is a example how to save more than one values on file separating its with "\r\n" and how to recovering its values.

Results:
First value (123) packed with 4 bytes
Separator \r\n with 2 bytes
Second value (456) packed with 4 bytes
The reading values is:
Array ( [1] => 123 ) 
Array ( [1] => 456 )
As with perl, the count for hex is number of nybbles or half-bytes, this differs from the other options which count in full bytes.
A simpler solution is to mask the value with 0xffffffff. For instance:

Unlike sprintf(), which converts the value to a string, this preserves the numeric type of the value.
Functions I found useful when dealing with fixed width file processing, related to unpack/pack functions. 
Above it says this:
 "Note that PHP internally stores integral values as signed. If you unpack a large unsigned long and it is of the same size as PHP internally stored values the result will be a negative number even though unsigned unpacking was specified."
This happened to me. I wanted to get a big number from a unsigned long, but it kept coming returning a negative. Happened to notice that sprintf('%u',$dta) will take the useless negative and restore it into its large unsigned proper magnitude.
Hope this saves someone a little time...
To convert big endian to little endian or to convert little endian to big endian, use the following approach as an example:

With the logic of the approach in this example, you can discover how to swap the endian byte order as you need.
I wrote a quick pair of functions using pack/unpack for converting between raw binary (e.g. openssl_random_pseudo_bytes() output) and hexadecimal (e.g. hash() output):

Feel free to suggest any improvements, but I thought this was worth sharing.
I hadn't realized that if the number after the unpack type was 1 (i.e. "V1page"), that it would behave as if there was no number at all. I had been using a variable and didn't think to watch for this. For instance,

Now if $something was FALSE, then $arr will only have one entry named "page". If $something was TRUE, $arr would have "page1" and "page2".
You might find these functions useful:

Of course, you can address byte strings as if they're arrays with numerical indexes, but the other functions are helpful.
Here is my solution to reading a Big-Endian formatted double on an Little-Endian machine. 

鹏仔微信 15129739599 鹏仔QQ344225443 鹏仔前端 pjxi.com 共享博客 sharedbk.com

免责声明:我们致力于保护作者版权,注重分享,当前被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理!邮箱:344225443@qq.com)

图片声明:本站部分配图来自网络。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

内容声明:本文中引用的各种信息及资料(包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主体(包括但不限于公司、媒体、协会等机构)的官方网站或公开发表的信息。部分内容参考包括:(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供参考使用,不准确地方联系删除处理!本站为非盈利性质站点,本着为中国教育事业出一份力,发布内容不收取任何费用也不接任何广告!)