Извлечь внутреннюю информацию 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;
}