Php 提取内部EXE信息

Php 提取内部EXE信息,php,exe,Php,Exe,Windows EXE文件有一些元数据,如CompanyName,FileVersion,InternalName,ProductName,OriginalFileName,ProductVersion,等等 如何使用PHP提取此类元数据?我对此很好奇,因此决定编写以下函数: function getFileVersionInfo($filename,$encoding='UTF-8'){ $dat = file_get_contents($filename); if($pos=

Windows EXE文件有一些元数据,如
CompanyName
FileVersion
InternalName
ProductName
OriginalFileName
ProductVersion
,等等


如何使用PHP提取此类元数据?

我对此很好奇,因此决定编写以下函数:

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>";
php.exe(32位):

jre-7u9-windows-x64.exe(64位):

关于
php.exe
的一些有趣的事情:详细信息选项卡中不会显示
注释
URL
。 至少在我的电脑里

享受

更新1:我忘记了错误检查。现在,如果版本信息不存在,它将返回null

更新2:非常感谢您提醒我注意编码问题

我添加了一个可选的第二个参数,该参数默认为UTF-8,在大多数情况下都可以使用。 如果需要单字节字符输出,请改用ISO-8859-1,如下所示:


这对我来说很有用。也适用于.dll-s

函数fsubstr($file\u handle,$start,$lenght)
{
fseek($file\u handle,$start);
$result=fread($file\u handle,$lenght);
返回$result;
}
函数fGetFileVersion($FileName)
{
$handle=fopen($FileName,'rb');
如果(!$handle)
{
返回FALSE;
}
$Header=fread($handle,64);
if(substr($Header,0,2)!='MZ')
{
返回FALSE;
}
$PEOffset=unpack(“V”,substr($Header,60,4));
如果($PEOffset[1]<64)
{
返回FALSE;
}
fseek($handle,$PEOffset[1],SEEK\u SET);
$Header=fread($handle,24);
if(substr($Header,0,2)!='PE')
{
返回FALSE;
}
$Machine=unpack(“v”,substr($Header,4,2));
如果($Machine[1]!=332)
{        
返回FALSE;
}
$NoSections=unpack(“v”,substr($Header,6,2));
$OptHdrSize=unpack(“v”,substr($Header,20,2));
fseek($handle,$OptHdrSize[1],SEEK\u CUR);
$ResFound=FALSE;
对于($x=0;$x<$NoSections[1];$x++)
{
$SecHdr=fread($handle,40);
如果(substr($SecHdr,0,5)='.rsrc')
{
$ResFound=TRUE;
打破
}
}
如果(!$ResFound)
{        
返回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;

对于x x=0;$x信息通常存储在Ext的.dll文件中,搜索“否”,它存储在EXE文件中,并且我可以用C++和C++来提取这些信息。我的问题是如何从PHP中读取这些信息。不一定可以检查一下,因为这是一个相当有趣的问题,而我可能永远不需要它。d有一天我会的,知道答案会很高兴!我没有在我的机器上安装它,所以我无法测试任何一个,但是有人知道是否有任何东西可以实现这一点吗?你看到了吗?@ray rardin--很好的工作伙伴,我可以肯定它在我这边工作(windows 2012 64位服务器)@Abela感谢您的确认和屏幕截图。我注意到了那里的版权符号。我可能应该将ISO-8859-1更改为UTF-8。是的,我实际上注意到,在拍摄并上传屏幕截图后,我立即将代码切换为使用
UTF-8
,解决了这个问题,我只是不想上传新图像。N现在看看@danielfcand是否会接受这个答案;)@Rei回答得很好。我有一个建议,限制
文件获取内容
,例如:
文件获取内容($filename,false,null,0,15728640);
。注意:15728640=1024*1024*15。我尝试了不同文件大小的不同限制,15728640适用于所有测试,小于此值会导致一些返回“null”…此建议是为了防止脚本在可执行文件太大且超出请求中的内存时死亡,这也有助于缩短响应时间…我的“完整建议”:@GuilhermeNascimento内存使用可能是一个问题,但限制大小不是解决方案。您似乎已经知道原因。正确的解决方案是将文件分块读取,例如,一次读取1 MB。这样,它将能够处理任何大小的文件,并且内存使用率将保持在较低水平。
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
)
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
)
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
)
getFileVersionInfo('php.exe','ISO-8859-1');
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]);
}