Извлечь внутреннюю информацию EXE

EXE-файлы Windows имеют некоторые метаданные, такие как CompanyName, FileVersion, InternalName, ProductName, OriginalFileName, ProductVersion, так далее.

Как извлечь такие метаданные из PHP?

2 ответа

Решение

Мне стало любопытно, поэтому я решил написать эту функцию:

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 не отображаются на вкладке Details. По крайней мере, в моем компьютере.

Наслаждаться.

Обновление 1: я забыл проверку ошибок. Теперь он возвращает ноль, если информация о версии не существует.

Обновление 2: Большое спасибо Abela за то, что обратили мое внимание на Abela с кодировкой.

Я добавил необязательный 2-й параметр, по умолчанию UTF-8, который должен работать в большинстве случаев. Если вам нужен вывод однобайтовых символов, используйте вместо этого ISO-8859-1, например так:

getFileVersionInfo('php.exe','ISO-8859-1');

Моя модификация. Для больших файлов. Сканирует VS_VERSION_INFO, читая файл по частям. Затем прочтите ИНФОРМАЦИЮ в памяти.

      function getFileVersionInfo($filename,$encoding='UTF-8')
{
    $fh = fopen($filename,'rb');

    if($pos=filestrpos($fh,mb_convert_encoding('VS_VERSION_INFO','UTF-16LE'))){
        $pos-= 6;
        $six = unpack('v*',filesubstr($fh,$pos,6));
        $dat = filesubstr($fh,$pos,$six[1]);
        $pos = strpos($dat,mb_convert_encoding('StringFileInfo','UTF-16LE'));
        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;
        }
    }
}

function filestrpos($file_handle,$search_string,$chunk_size=1024*1024)
{
    if (strlen($search_string) > 2 * $chunk_size) {
        $chunk_size = strlen($search_string) * 2;
    }
    $current_offset = ftell($file_handle);
    $last_buffer = '';
    $position = false;
    while (!feof($file_handle)) {
        $chunk = fread($file_handle,$chunk_size);
        $buffer = $last_buffer . $chunk;
        $position_in_buffer = strpos($buffer, $search_string);
        if ($position_in_buffer !== false) {
            // Return position of string in file
            $position = ftell($file_handle) - strlen($buffer) + $position_in_buffer ;
            break;
        }
        $last_buffer = $chunk;
    }
    fseek($file_handle,$current_offset,SEEK_SET);
    return $position;    
}

function filesubstr($file_handle,$start,$lenght)
{
    fseek($file_handle,$start);
    $result = fread($file_handle,$lenght);
    return $result;
}
Другие вопросы по тегам