Получить версию exe через PHP - PullRequest
19 голосов
/ 08 января 2010

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

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

Ответы [ 7 ]

21 голосов
/ 29 января 2010

Я хотел то же самое, поэтому я написал это: Возвращает 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;
}
11 голосов
/ 19 июля 2011

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

Обратите внимание, что при этом файлы сканируются в виде фрагментов по 64 КБ в поисках строки $ key. Если у вас большой .exe, это может занять несколько секунд. Мой .exe 52k, так что это почти мгновенно. Если у вас есть большой исполняемый файл, вы можете изменить сканирование.

<?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");
?>
11 голосов
/ 08 января 2010

На машине 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

5 голосов
/ 08 января 2010

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

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

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

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

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

1 голос
/ 17 июля 2017

Я объединил ответы вместе и добавил исправление 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;
}
1 голос
/ 04 сентября 2014

уточняю ответ, предоставленный Тони Один из проектов в работе имел собственный атрибут, запеченный в этом разделе ресурсов. На 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');
0 голосов
/ 17 мая 2017

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

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 уже добавило в комментарии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...