Windows EXE文件包含一些元数据,如CompanyName
,FileVersion
,InternalName
,ProductName
,OriginalFileName
,ProductVersion
等。
如何使用PHP提取此类元数据?
答案 0 :(得分:4)
我对此感到好奇,所以我决定写这个函数:
function getFileVersionInfo($filename,$encoding='UTF-8'){
$dat = file_get_contents($filename);
if($pos=strpos($dat,mb_convert_encoding('VS_VERSION_INFO','UTF-16LE'))){
$pos-= 6;
$six = unpack('v*',substr($dat,$pos,6));
$dat = substr($dat,$pos,$six[1]);
if($pos=strpos($dat,mb_convert_encoding('StringFileInfo','UTF-16LE'))){
$pos+= 54;
$res = [];
$six = unpack('v*',substr($dat,$pos,6));
while($six[2]){
$nul = strpos($dat,"\0\0\0",$pos+6)+1;
$key = mb_convert_encoding(substr($dat,$pos+6,$nul-$pos-6),$encoding,'UTF-16LE');
$val = mb_convert_encoding(substr($dat,ceil(($nul+2)/4)*4,$six[2]*2-2),$encoding,'UTF-16LE');
$res[$key] = $val;
$pos+= ceil($six[1]/4)*4;
$six = unpack('v*',substr($dat,$pos,6));
}
return $res;
}
}
}
它适用于32位和64位exe。用法示例:
echo "<pre>".print_r(getFileVersionInfo('notepad.exe'),1)."</pre>";
echo "<pre>".print_r(getFileVersionInfo('php.exe'),1)."</pre>";
echo "<pre>".print_r(getFileVersionInfo('jre-7u9-windows-x64.exe'),1)."</pre>";
notepad.exe(32位):
Array
(
[CompanyName] => Microsoft Corporation
[FileDescription] => Notepad
[FileVersion] => 6.1.7600.16385 (win7_rtm.090713-1255)
[InternalName] => Notepad
[LegalCopyright] => © Microsoft Corporation. All rights reserved.
[OriginalFilename] => NOTEPAD.EXE
[ProductName] => Microsoft® Windows® Operating System
[ProductVersion] => 6.1.7600.16385
)
php.exe(32位):
Array
(
[Comments] => Thanks to Edin Kadribasic, Marcus Boerger, Johannes Schlueter, Moriyoshi Koizumi, Xinchen Hui
[CompanyName] => The PHP Group
[FileDescription] => CLI
[FileVersion] => 7.0.12
[InternalName] => CLI SAPI
[LegalCopyright] => Copyright © 1997-2016 The PHP Group
[LegalTrademarks] => PHP
[OriginalFilename] => php.exe
[ProductName] => PHP
[ProductVersion] => 7.0.12
[URL] => http://www.php.net
)
jre-7u9-windows-x64.exe(64位):
Array
(
[CompanyName] => Oracle Corporation
[FileDescription] => Java(TM) Platform SE binary
[FileVersion] => 7.0.90.5
[Full Version] => 1.7.0_09-b05
[InternalName] => Setup Launcher
[LegalCopyright] => Copyright © 2012
[OriginalFilename] => jinstall.exe
[ProductName] => Java(TM) Platform SE 7 U9
[ProductVersion] => 7.0.90.5
)
有关php.exe
的有趣内容:Comments
和URL
未显示在“详细信息”标签中。
至少在我的电脑里。
享受。
更新1:我忘记了错误检查。现在,如果版本信息不存在,它将返回null。
更新2 :非常感谢@Abela提醒我注意编码问题。
我添加了一个可选的第二个参数,默认为UTF-8,它应该适用于大多数用途。 如果您需要单字节字符输出,请使用ISO-8859-1,如下所示:
getFileVersionInfo('php.exe','ISO-8859-1');
答案 1 :(得分:0)
这对我有用。也适用于 .dll-s。
function fsubstr($file_handle,$start,$lenght)
{
fseek($file_handle,$start);
$result = fread($file_handle,$lenght);
return $result;
}
function fGetFileVersion($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++)
{
$SecHdr = fread($handle, 40);
if (substr($SecHdr, 0, 5) == '.rsrc')
{
$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));
$offset = $InfoOff[1];
$NumDirs = unpack("v", fsubstr($handle, $offset + 14, 2));
$InfoFound = FALSE;
for ($x = 0; $x <$NumDirs[1]; $x++)
{
$Type = unpack("V", fsubstr($handle, $offset + ($x * 8) + 16, 4));
if($Type[1] == 16)
{
//FILEINFO resource
$InfoFound = TRUE;
$SubOff = unpack("V", fsubstr($handle, $offset + ($x * 8) + 20, 4));
break;
}
}
if (!$InfoFound)
{
return FALSE;
}
$SubOff[1] &= 0x7fffffff;
$InfoOff = unpack("V", fsubstr($handle, $offset + $SubOff[1] + 20, 4)); //offset of first FILEINFO
$InfoOff[1] &= 0x7fffffff;
$InfoOff = unpack("V", fsubstr($handle, $offset + $InfoOff[1] + 20, 4)); //offset to data
$DataOff = unpack("V", fsubstr($handle, $offset + $InfoOff[1], 4));
$DataSize = unpack("V", fsubstr($handle, $offset + $InfoOff[1] + 4, 4));
$CodePage = unpack("V", fsubstr($handle, $offset + $InfoOff[1] + 8, 4));
$DataOff[1] -= $InfoVirt[1];
$Version = unpack("v4", fsubstr($handle, $offset + $DataOff[1] + 48, 8));
return sprintf("%u.%u.%u.%u",$Version[2],$Version[1],$Version[4],$Version[3]);
}