小智 22
我想要相同的东西,所以我编写了这个:它返回FALSE,如果它无法获取版本信息,或者返回带有文件版本字段的四个元素的ARRAY(数字,由...分隔).它仅适用于32-位PE文件(因为我不需要其他格式).
function GetFileVersion($FileName) {
$handle=fopen($FileName,'rb');
if (!$handle) return FALSE;
$Header=fread ($handle,64);
if (substr($Header,0,2)!='MZ') return FALSE;
$PEOffset=unpack("V",substr($Header,60,4));
if ($PEOffset[1]<64) return FALSE;
fseek($handle,$PEOffset[1],SEEK_SET);
$Header=fread ($handle,24);
if (substr($Header,0,2)!='PE') return FALSE;
$Machine=unpack("v",substr($Header,4,2));
if ($Machine[1]!=332) return FALSE;
$NoSections=unpack("v",substr($Header,6,2));
$OptHdrSize=unpack("v",substr($Header,20,2));
fseek($handle,$OptHdrSize[1],SEEK_CUR);
$ResFound=FALSE;
for ($x=0;$x<$NoSections[1];$x++) { //$x fixed here
$SecHdr=fread($handle,40);
if (substr($SecHdr,0,5)=='.rsrc') { //resource section
$ResFound=TRUE;
break;
}
}
if (!$ResFound) return FALSE;
$InfoVirt=unpack("V",substr($SecHdr,12,4));
$InfoSize=unpack("V",substr($SecHdr,16,4));
$InfoOff=unpack("V",substr($SecHdr,20,4));
fseek($handle,$InfoOff[1],SEEK_SET);
$Info=fread($handle,$InfoSize[1]);
$NumDirs=unpack("v",substr($Info,14,2));
$InfoFound=FALSE;
for ($x=0;$x<$NumDirs[1];$x++) {
$Type=unpack("V",substr($Info,($x*8)+16,4));
if($Type[1]==16) { //FILEINFO resource
$InfoFound=TRUE;
$SubOff=unpack("V",substr($Info,($x*8)+20,4));
break;
}
}
if (!$InfoFound) return FALSE;
$SubOff[1]&=0x7fffffff;
$InfoOff=unpack("V",substr($Info,$SubOff[1]+20,4)); //offset of first FILEINFO
$InfoOff[1]&=0x7fffffff;
$InfoOff=unpack("V",substr($Info,$InfoOff[1]+20,4)); //offset to data
$DataOff=unpack("V",substr($Info,$InfoOff[1],4));
$DataSize=unpack("V",substr($Info,$InfoOff[1]+4,4));
$CodePage=unpack("V",substr($Info,$InfoOff[1]+8,4));
$DataOff[1]-=$InfoVirt[1];
$Version=unpack("v4",substr($Info,$DataOff[1]+48,8));
$x=$Version[2];
$Version[2]=$Version[1];
$Version[1]=$x;
$x=$Version[4];
$Version[4]=$Version[3];
$Version[3]=$x;
return $Version;
}
Run Code Online (Sandbox Code Playgroud)
小智 12
我最近把我们的托管从Windows搬到了Linux.考虑到Microsoft对象,使用VBScript非常容易,但在Linux和PHP上我找不到任何东西.我们在PHP中编写了这个函数来扫描.exe文件并提取VB.Net应用程序中的"产品版本".您可以将$ key更改为您可以找到的具有版本信息和空终止符的任何字符串.
请注意,这将以64k块的形式扫描文件,以查找$ key字符串.如果你有一个大的.exe,可能需要几秒钟.我的.exe是52k所以它几乎是即时的.如果您有更大的exe,则可以更改扫描.
<?php
function get_product_version($file_name)
{
$key = "P\x00r\x00o\x00d\x00u\x00c\x00t\x00V\x00e\x00r\x00s\x00i\x00o\x00n\x00\x00\x00";
$fptr = fopen($file_name, "rb");
$data = "";
while (!feof($fptr))
{
$data .= fread($fptr, 65536);
if (strpos($data, $key)!==FALSE)
break;
$data = substr($data, strlen($data)-strlen($key));
}
fclose($fptr);
if (strpos($data, $key)===FALSE)
return "";
$pos = strpos($data, $key)+strlen($key);
$version = "";
for ($i=$pos; $data[$i]!="\x00"; $i+=2)
$version .= $data[$i];
return $version;
}
echo get_product_version("/path_to_file/foo.exe");
?>
Run Code Online (Sandbox Code Playgroud)
Vol*_*erK 11
在win32机器上,您可以使用COM扩展和FileSystemObject.GetFileVersion()方法来检索版本信息.例如
$path = getenv('SystemRoot').'\\NOTEPAD.EXE';
$fso = new COM('Scripting.FileSystemObject');
echo $path, ' : ', $fso->GetFileVersion($path);
Run Code Online (Sandbox Code Playgroud)
打印(在我的机器上) C:\WINDOWS\NOTEPAD.EXE : 5.1.2600.5512
我假设你不在Windows上,你的意思是可以存储在Windows可执行文件中的版本信息,并在Windows资源管理器中弹出这样一个文件的属性对话框.
此信息似乎存储在VS_VERSION_INFO可执行文件的块中(请参阅此问题).我不知道任何工具以简单的方式提取这些信息,甚至在Windows本身也是如此.
似乎有几种方法可以通过Windows API获取此信息(请参阅此处的Perl示例),但我无法通过解析可执行文件看到任何"从头开始"工作的方法.
如果您稍微挖掘一下,您可能会找到一个文件格式说明,解释如何VS_VERSION_INFO从EXE文件中读取信息.但是,要做好大量工作以使其可靠地工作.
如果你想这样做,准备投入大量的时间和精力.