<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></title> 
<link>http://www.jackxiang.com/index.php</link> 
<description><![CDATA[赢在IT，Playin' with IT,Focus on Killer Application,Marketing Meets Technology.]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></copyright>
<item>
<link>http://www.jackxiang.com/post//</link>
<title><![CDATA[ php读取二进制流（C语言结构体struct数据文件）]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[WEB2.0]]></category>
<pubDate>Mon, 28 Apr 2008 09:22:36 +0000</pubDate> 
<guid>http://www.jackxiang.com/post//</guid> 
<description>
<![CDATA[ 
	<p>来源：<a href="http://bianbian.org/technology/295.html">http://bianbian.org/technology/295.html</a><br />用PHP生成结构体:<br /><a href="http://bbs.chinaunix.net/viewthread.php?tid=1034276">http://bbs.chinaunix.net/viewthread.php?tid=1034276</a><br />尽管php是用C语言开发的，不过令我不解的是php没有提供对结构体struct的直接支持。<br />不过php提供了pack和unpack函数，用来进行二进制数据（binary data）和php内部数据的互转：</p><div class="hl-surround"><ol class="hl-main ln-show"><li class="hl-firstline"><span style="color: blue">string</span><span style="color: gray"> </span><span style="color: blue">pack</span><span style="color: gray"> </span><span style="color: olive">(</span><span style="color: gray"> </span><span style="color: blue">string</span><span style="color: gray"> </span><span style="color: #00008b">$format</span><span style="color: gray"> </span><span style="color: olive">[</span><span style="color: gray">, </span><span style="color: blue">mixed</span><span style="color: gray"> </span><span style="color: #00008b">$args</span><span style="color: gray"> </span><span style="color: olive">[</span><span style="color: gray">, </span><span style="color: blue">mixed</span><span style="color: gray"> $...</span><span style="color: olive">]]</span><span style="color: gray"> </span><span style="color: olive">)</span> </li><li><span style="color: #ffa500">//Pack given arguments into binary string according to format. </span></li><li><span style="color: green">array</span><span style="color: gray"> </span><span style="color: blue">unpack</span><span style="color: gray"> </span><span style="color: olive">(</span><span style="color: gray"> </span><span style="color: blue">string</span><span style="color: gray"> </span><span style="color: #00008b">$format</span><span style="color: gray">, </span><span style="color: blue">string</span><span style="color: gray"> </span><span style="color: #00008b">$data</span><span style="color: gray"> </span><span style="color: olive">)</span> </li><li><span style="color: #ffa500">//Unpacks from a binary string into an array according to the given format.</span> </li></ol></div><p>其中，$format跟perl里的pack格式类似，有如下一些（中文是我加的，有不准确的欢迎提出）：<br />a NUL-padded string，即&ldquo;&#92;0&rdquo;作为&ldquo;空字符&rdquo;的表示形式<br />A SPACE-padded string，空格作为&ldquo;空字符&rdquo;的表示形式<br />h Hex string, low nibble first，升序位顺序<br />H Hex string, high nibble first，降序位顺序<br />c signed char，有符号单字节<br />C unsigned char，无符号单字节<br />s signed short (always 16 bit, machine byte order)<br />S unsigned short (always 16 bit, machine byte order)<br />n unsigned short (always 16 bit, big endian byte order)<br />v unsigned short (always 16 bit, little endian byte order)<br />i signed integer (machine dependent size and byte order)<br />I unsigned integer (machine dependent size and byte order)<br />l signed long (always 32 bit, machine byte order)<br />L unsigned long (always 32 bit, machine byte order)<br />N unsigned long (always 32 bit, big endian byte order)<br />V unsigned long (always 32 bit, little endian byte order)<br />f float (machine dependent size and representation)<br />d double (machine dependent size and representation)<br />x NUL byte，实际使用的时候作为跳过多少字节用，很有用<br />X Back up one byte，后退1字节<br />@ NUL-fill to absolute position，实际使用的时候作为从开头跳到某字节用，很有用</p><p>实际使用发现：C里的&ldquo;&#92;0&rdquo;（即字符串终止符）在php里并不是终止符，而是作为了字符串的一部分。因此，必须对&ldquo;&#92;0&rdquo;进行特殊处理，才能进行struct和php内部数据的完美互转。比如 char name[10]; 如果实际数据是&ldquo;62 69 61 6E 00 62 69 61 6E 00&rdquo;，在C语言里第5个位置有终止符，name应该是&ldquo;bian&rdquo;；而用了unpack转换以后在php里的name却是&ldquo;bian&#92;0bian&#92;0&rdquo;。<br />一开始我用了strpos函数找到&ldquo;&#92;0&rdquo;的位置，然后进行substr截取：</p><div class="hl-surround"><ol class="hl-main ln-show"><li class="hl-firstline"><span style="color: #00008b">$name</span><span style="color: gray"> = </span><span style="color: blue">substr</span><span style="color: olive">(</span><span style="color: #00008b">$name</span><span style="color: gray">, </span><span style="color: maroon">0</span><span style="color: gray">, </span><span style="color: blue">strpos</span><span style="color: olive">(</span><span style="color: #00008b">$name</span><span style="color: gray">, </span><span style="color: #8b0000">&quot;</span><span style="color: red">&#92;0</span><span style="color: #8b0000">&quot;</span><span style="color: olive">))</span><span style="color: gray">;</span> </li></ol></div><p>不过很Faint的事情发生了，不知道是strpos的bug还是substr的bug（其实测试一下就知道，懒得试），有些字符串没问题，有些字符串却只能得到空值（即$name == &rdquo;）。很是郁闷，后来找了个strtok函数，这下没有问题了：</p><div class="hl-surround"><ol class="hl-main ln-show"><li class="hl-firstline"><span style="color: #00008b">$name</span><span style="color: gray"> = </span><span style="color: blue">strtok</span><span style="color: olive">(</span><span style="color: #00008b">$name</span><span style="color: gray">, </span><span style="color: #8b0000">&quot;</span><span style="color: red">&#92;0</span><span style="color: #8b0000">&quot;</span><span style="color: olive">)</span><span style="color: gray">;</span> </li></ol></div><p>难为大家看了那么多，下面写个完整的php读取二进制数据流（C语言结构体struct数据）文件的示例代码：<br />首先是C的struct定义示例，为了演示，我就写个简单点的，实际对照上面那个$format格式表应该没有问题：</p><div class="hl-surround"><ol class="hl-main ln-show"><li class="hl-firstline"><span class="hl-types">struct</span><span style="color: gray"> </span><span style="color: blue">BIANBIAN</span><span style="color: gray"> </span><span style="color: olive">&#123;</span> </li><li><span class="hl-types">char</span><span style="color: gray"> </span><span style="color: blue">name</span><span style="color: olive">[</span><span style="color: maroon">10</span><span style="color: olive">]</span><span style="color: gray">;</span> </li><li><span class="hl-types">char</span><span style="color: gray"> </span><span style="color: blue">pass</span><span style="color: olive">[</span><span style="color: maroon">33</span><span style="color: olive">]</span><span style="color: gray">;</span> </li><li><span class="hl-types">int</span><span style="color: gray"> </span><span style="color: blue">age</span><span style="color: gray">;</span> </li><li><span class="hl-types">unsigned</span><span style="color: gray"> </span><span class="hl-types">char</span><span style="color: gray"> </span><span style="color: blue">flag</span><span style="color: gray">;</span> </li><li><span style="color: olive">&#125;</span><span style="color: gray">;</span></li></ol></div><p>比如有个&ldquo;bianbian.org&rdquo;文件，内容就是上面的N个BIANBIAN结构体构成的。读取的php代码：</p><div class="hl-surround"><ol class="hl-main ln-show"><li class="hl-firstline"><span style="color: #ffa500">//下面根据struct确定$format，注意int类型跟机器环境有关，我的32位Linux是4个长度</span> </li><li><span style="color: #00008b">$format</span><span style="color: gray"> = </span><span style="color: #8b0000">'</span><span style="color: red">a10name/a33pass/iage/Cflag</span><span style="color: #8b0000">'</span><span style="color: gray">;</span> </li><li><span style="color: #ffa500">//确定一个struct占用多少长度字节，如果只是读取单个结构体这是不需要的</span> </li><li><span style="color: #00008b">$length</span><span style="color: gray"> = </span><span style="color: maroon">10</span><span style="color: gray"> + </span><span style="color: maroon">33</span><span style="color: gray"> + </span><span style="color: maroon">4</span><span style="color: gray"> + </span><span style="color: maroon">1</span><span style="color: gray">;</span> </li><li><span style="color: #ffa500">//也可以用fopen + fread + fclose，不过file_get_contents因为可以mmap，效率更高</span> </li><li><span style="color: #00008b">$data</span><span style="color: gray"> = </span><span style="color: blue">file_get_contents</span><span style="color: olive">(</span><span style="color: #8b0000">'</span><span style="color: red">bianbian.org</span><span style="color: #8b0000">'</span><span style="color: gray">, </span><span style="color: #8b0000">'</span><span style="color: red">r</span><span style="color: #8b0000">'</span><span style="color: olive">)</span><span style="color: gray">;</span> </li><li><span style="color: green">for</span><span style="color: gray"> </span><span style="color: olive">(</span><span style="color: #00008b">$i</span><span style="color: gray"> = </span><span style="color: maroon">0</span><span style="color: gray">, </span><span style="color: #00008b">$c</span><span style="color: gray"> = </span><span style="color: blue">strlen</span><span style="color: olive">(</span><span style="color: #00008b">$data</span><span style="color: olive">)</span><span style="color: gray">; </span><span style="color: #00008b">$i</span><span style="color: gray"> &lt; </span><span style="color: #00008b">$c</span><span style="color: gray">; </span><span style="color: #00008b">$i</span><span style="color: gray"> += </span><span style="color: #00008b">$length</span><span style="color: olive">)</span><span style="color: gray"> </span><span style="color: olive">&#123;</span> </li><li><span style="color: #00008b">$bianbian</span><span style="color: gray"> = </span><span style="color: blue">unpack</span><span style="color: olive">(</span><span style="color: #8b0000">&quot;</span><span style="color: red">@</span><span style="color: #00008b">$i</span><span style="color: red">/</span><span style="color: #00008b">$format</span><span style="color: #8b0000">&quot;</span><span style="color: gray">, </span><span style="color: #00008b">$data</span><span style="color: olive">)</span><span style="color: gray">;</span> </li><li><span style="color: #ffa500">//reference传递是php 5才支持的，如果用php4，得用其他办法</span> </li><li><span style="color: green">foreach</span><span style="color: gray"> </span><span style="color: olive">(</span><span style="color: #00008b">$bianbian</span><span style="color: gray"> </span><span style="color: green">as</span><span style="color: gray"> &amp;</span><span style="color: #00008b">$value</span><span style="color: olive">)</span><span style="color: gray"> </span><span style="color: olive">&#123;</span> </li><li><span style="color: green">if</span><span style="color: gray"> </span><span style="color: olive">(</span><span style="color: blue">is_string</span><span style="color: olive">(</span><span style="color: #00008b">$value</span><span style="color: olive">))</span><span style="color: gray"> </span><span style="color: olive">&#123;</span> </li><li><span style="color: #00008b">$value</span><span style="color: gray"> = </span><span style="color: blue">strtok</span><span style="color: olive">(</span><span style="color: #00008b">$value</span><span style="color: gray">, </span><span style="color: #8b0000">&quot;</span><span style="color: red">&#92;0</span><span style="color: #8b0000">&quot;</span><span style="color: olive">)</span><span style="color: gray">;</span> </li><li><span style="color: olive">&#125;</span> </li><li><span style="color: olive">&#125;</span> </li><li><span style="color: blue">print_r</span><span style="color: olive">(</span><span style="color: #00008b">$bianbian</span><span style="color: olive">)</span><span style="color: gray">;</span> </li><li><span style="color: olive">&#125;</span> </li><li><span style="color: #ffa500">//输出为array，即类似：</span> </li><li><span style="color: green">Array</span> </li><li><span style="color: olive">(</span> </li><li><span style="color: olive">[</span><span style="color: blue">name</span><span style="color: olive">]</span><span style="color: gray"> =&gt; </span><span style="color: #8b0000">'</span><span style="color: red">bianbian</span><span style="color: #8b0000">'</span> </li><li><span style="color: olive">[</span><span style="color: blue">pass</span><span style="color: olive">]</span><span style="color: gray"> =&gt; </span><span style="color: #8b0000">'</span><span style="color: red">bianbian.org</span><span style="color: #8b0000">'</span> </li><li><span style="color: olive">[</span><span style="color: blue">age</span><span style="color: olive">]</span><span style="color: gray"> =&gt; </span><span style="color: maroon">100</span> </li><li><span style="color: olive">[</span><span style="color: blue">flag</span><span style="color: olive">]</span><span style="color: gray"> =&gt; </span><span style="color: maroon">0</span> </li><li><span style="color: olive">)</span> </li><li><span style="color: gray">...</span> </li></ol></div><p>pack应该跟unpack相反</p><br/><br/><br/><br/><br/>==================================================<br/>实际使用发现：C里的“&#92;0”（即字符串终止符）在php里并不是终止符，而是作为了字符串的一部分。因此，必须对“&#92;0”进行特殊处理，才能进行 struct和php内部数据的完美互转。比如 char name[10]; 如果实际数据是“62 69 61 6E 00 62 69 61 6E 00”，在C语言里第5个位置有终止符，name应该是“bian”；而用了unpack转换以后在php里的name却是“bian&#92;0bian &#92;0”。<br/>一开始我用了strpos函数找到“&#92;0”的位置，然后进行substr截取.<br/>不过很Faint的事情发生了，不知道是strpos的bug还是substr的bug（其实测试一下就知道，懒得试），有些字符串没问题，有些字符串却只能得到空值（即$name == ”）。很是郁闷，后来找了个strtok函数，这下没有问题了.<br/>难为大家看了那么多，下面写个完整的php读取二进制数据流（C语言结构体struct数据）文件的示例代码：<br/>首先是C的struct定义示例，为了演示，我就写个简单点的，实际对照上面那个$format格式表应该没有问题：<br/>struct TEST&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;char name[10];<br/>&nbsp;&nbsp;&nbsp;&nbsp;char pass[33];<br/>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;age;<br/>&nbsp;&nbsp;&nbsp;&nbsp;unsigned char flag;<br/>&#125;;<br/> 比如有个“file.dat”文件，内容就是上面的N个BIANBIAN结构体构成的。读取的php代码：<br/>&nbsp;&nbsp;&nbsp;&nbsp;<?php&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp; //下面根据struct确定$format，注意int类型跟机器环境有关，我的32位Linux是4个长度&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp; $format = 'a10name/a33pass/iage/Cflag';&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp; //确定一个struct占用多少长度字节，如果只是读取单个结构体这是不需要的&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp; $length = 10 + 33 + 4 + 1;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp; //也可以用fopen + fread + fclose，不过file_get_contents因为可以mmap，效率更高&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp; $data = file_get_contents('file.dat', 'r');&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp; for ($i = 0, $c = strlen($data); $i < $c; $i += $length) &#123;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $bianbian = unpack("$format", $data);&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //reference传递是php 5才支持的，如果用php4，得用其他办法&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach ($bianbian as &$value) &#123;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (is_string($value)) &#123;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $value = strtok($value, "&#92;0");&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#125;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#125;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print_r($bianbian);&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp; &#125;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;?> <br/>pack应该跟unpack相反。<br/>顺便附上生成结构体文件的C语言代码：<br/>&nbsp;&nbsp;&nbsp;&nbsp;#include <stdio.h>&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;#include <string.h>&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;struct example&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#123;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char name[10];&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char pass[33];&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;age;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned char flag;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;int main()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#123;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;example test;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;example read;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FILE *fp;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;test.age = 111;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;test.flag = 10;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy(test.name, "Hello World!");&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy(test.pass, "zbl110119");&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fp = fopen("file.dat", "w+");&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!fp)&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("open file error!");&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return -1;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rewind(fp);&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fwrite(&test, sizeof(example), 1, fp);&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rewind(fp);&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fread(&read, sizeof(example), 1, fp);&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("%d, %s&#92;n", read.age, read.name);&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fclose(fp);&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125; 
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post//#blogcomment</link>
<title><![CDATA[[评论]  php读取二进制流（C语言结构体struct数据文件）]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>http://www.jackxiang.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>