Подтвердить что ты не робот

Получить версию exe через PHP

Получается ли версия exe с php? Я хотел бы распечатать версию файла, который можно загрузить...

Windows exe и php работают на сервере linux

4b9b3361

Ответ 1

Мне хотелось того же самого, поэтому я закодировал это:  Он возвращает 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;
}

Ответ 2

На машине win32 вы можете использовать расширение COM и FileSystemObject. GetFileVersion() для получения информации о версии. например.

$path = getenv('SystemRoot').'\\NOTEPAD.EXE';
$fso = new COM('Scripting.FileSystemObject');
echo $path, ' : ', $fso->GetFileVersion($path);

печатает (на моей машине) C:\WINDOWS\NOTEPAD.EXE : 5.1.2600.5512

Ответ 3

Недавно я перевел наш хостинг из Windows в Linux. Это было довольно легко сделать с VBScript с учетом объектов Microsoft, но в Linux и PHP я ничего не мог найти. Мы написали эту функцию в PHP, чтобы отсканировать файл .exe и извлечь "Версию продукта", в которой было приложение VB.Net. Вы можете изменить ключ $, чтобы быть любой строкой, которую вы можете найти с информацией о версии и нулевым терминатором.

Обратите внимание, что это сканирует файлы в 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");
?>

Ответ 4

Я предполагаю, что вы не в Windows, и вы имеете в виду информацию о версии, которая может быть сохранена в исполняемых файлах Windows, и появляется в диалоговом окне свойств для такого файла в проводнике Windows.

Эта информация хранится в блоке VS_VERSION_INFO исполняемого файла (см., например, этот вопрос). Я не знаю никакого инструмента, который извлекает эту информацию простым способом, даже не в самой Windows.

Кажется, есть несколько способов получить эту информацию через Windows API (см. пример Perl здесь), но я могу "Посмотрите какой-либо подход, который работает" с нуля", просто анализируя исполняемый файл.

Если вы копаете немного, вы можете найти описание формата файла, в котором объясняется, как читать информацию VS_VERSION_INFO из EXE файла. Будьте готовы к большой работе, чтобы заставить это работать надежно, однако.

Будьте готовы потратить много времени и сил, если вы хотите это сделать.

Ответ 5

Разрабатывая ответ Тони Один из проектов на рабочем месте имел собственный атрибут, запеченный в этой секции ресурсов. На машине linux мы не хотели устанавливать perl для использования функции windows для получения значений. Вместо этого можно использовать этот вариант GetFileVersion для получения любого значения, которое вы ищете. (FileVersion, ProductVersion, ProductName, CompanyName, CompanyWebsite) Он должен возвращать false для значений, которые не существуют, и он функционирует довольно быстро.   

    $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') {         //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));
                    //echo $Info;
                    break;
            }
    }
    if (!$InfoFound) return FALSE;

    // i bypassed this, but if you knew the layout you could prolly do a little better then $ulgyRemainderOfData
    /*
    $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));

    // swap 1-2 3-4 / endian ecoding issue
    $x=$Version[2];
    $Version[2]=$Version[1];
    $Version[1]=$x;
    $x=$Version[4];
    $Version[4]=$Version[3];
    $Version[3]=$x;
    return $Version;
    */

    //view data...
    //echo print_r(explode("\x00\x00\x00", $Info));
    // could prolly substr on VS_VERSION_INFO
    $encodedKey = implode("\x00",str_split($seeking));
    $StartOfSeekingKey = strpos($Info, $encodedKey);
    if ($StartOfSeekingKey !== false) {
        $ulgyRemainderOfData = substr($Info, $StartOfSeekingKey);

        $ArrayOfValues = explode("\x00\x00\x00", $ulgyRemainderOfData);
        // the key your are seeking is 0, where the value is one
        return trim($ArrayOfValues[1]);
    }

    return false;
}


$fileVersion = GetValueOfSeeking("./the/path/to/some.exe", 'FileVersion');
$myAttribute = GetValueOfSeeking("./the/path/to/some.exe", 'CustomAttribute');

Ответ 6

Чтобы получить код от Toni для работы, мне пришлось сделать небольшое изменение:

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,16,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;
}

Где я только изменил 14 - 16 в строке

$NumDirs=unpack("v",substr($Info,16,2));

Возможно, это связано с тем, что j_schultz уже добавил в комментариях.

Ответ 7

Я объединил ответы вместе и добавил исправление NamedDirs. Также хочу подчеркнуть, что не использовать код NeuD, смещение должно оставаться 16; 14 определенно неверно. Надеюсь, это поможет кому-то.

function GetFileVersion($FileName)
{
    return GetValueOfSeeking($FileName, "FileVersion");
}

function GetValueOfSeeking($FileName, $seeking)
{
    $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]);

    $NumNamedDirs = unpack("v",substr($Info, 12, 2));
    $NumDirs = unpack("v", substr($Info, 14, 2));

    $InfoFound = FALSE;
    for ($x = 0; $x < ($NumDirs[1] + $NumNamedDirs[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;

    if (0)
    {
        $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;
    }

    //view data...
    //echo print_r(explode("\x00\x00\x00", $Info));
    // could prolly substr on VS_VERSION_INFO
    $encodedKey = implode("\x00",str_split($seeking));
    $StartOfSeekingKey = strpos($Info, $encodedKey);
    if ($StartOfSeekingKey !== false) {
        $ulgyRemainderOfData = substr($Info, $StartOfSeekingKey);
        $ArrayOfValues = explode("\x00\x00\x00", $ulgyRemainderOfData);
        // the key your are seeking is 0, where the value is one
        return trim($ArrayOfValues[1]);
    }

    return false;
}