Get Version of exe via PHP

前端 未结 8 1395
自闭症患者
自闭症患者 2020-12-08 11:14

Is getting the version of a exe possible with php? I\'d like to print the version of a file that can be downloaded...

Windows exe and php is running on linux server<

相关标签:
8条回答
  • 2020-12-08 11:29

    Elaborating on the answer Toni provided One of the projects at work had a custom attribute baked into that resource section. On a linux machine we didnt want to install perl to use the windows function to get the values. Instead one can use this variant of the GetFileVersion to get any value you are seeking. (FileVersion, ProductVersion, ProductName, CompanyName, CompanyWebsite) It should return false for values that dont exist, and it functions rather quick.

        $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 讨论(0)
  • 2020-12-08 11:29

    I wrote a small code that will pull the file version directly from the executable.

    PHP:

    <?php
    
    function exeparser_fileversion($file) {
        $parser_model = array('begin'=>"F\x00i\x00l\x00e\x00V\x00e\x00r\x00s\x00i\x00o\x00n",'end'=>"\x00\x00\x00");
        if (file_exists($file) && is_readable($file)) {
            $version = file_get_contents($file);
            $version = explode($parser_model['begin'], $version);
            $version = explode($parser_model['end'], $version[1]);
            $version = str_replace("\x00", null, $version[1]);
            return ((!empty($version) ? "\x1b[32m$file version: $version\x1b[0m" : "\x1b[31mNo version\x1b[0m"));
        } else {
            print "\x1b[31m".(is_dir($file) ? "Specified path points to a directory, not a file." : "The specified path to the file may not exist or is not a file at all.")."\x1b[0m";
            return false;
        }
    }
    
    @print exeparser_fileversion($argv[1]);
    
    ?>
    


    Windows command (optional):

    @php "%~dp0\exeparser.php" %*
    

    Result:

    0 讨论(0)
  • 2020-12-08 11:31

    On a win32 machine you can use the COM extension and FileSystemObject.GetFileVersion() method to retrieve the version info. e.g.

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

    prints (on my machine) C:\WINDOWS\NOTEPAD.EXE : 5.1.2600.5512

    0 讨论(0)
  • 2020-12-08 11:38

    I am assuming you're not on Windows, and you mean the Version information that can be stored in Windows executables, and pops up in the properties dialog for such a file in Windows Explorer.

    This information seems to be stored in the VS_VERSION_INFO block of an executable (see for example this question). I don't know any tool that extracts this information in a simple way, not even on Windows itself.

    There seem to be several ways to get hold of this information via the Windows API (See a Perl example here) but I can't see any approach that works "from scratch" by just parsing the executable.

    If you dig around a bit, you might be able to find a file format description that explains how to read the VS_VERSION_INFO information from an EXE file. Be prepared for a lot of work to get this to work reliably, though.

    Be prepared to invest a lot of time and effort if you want to do this.

    0 讨论(0)
  • 2020-12-08 11:44

    I wanted the same thing, so I coded this: It returns FALSE, if it can't get the version info, or an ARRAY of four elements with file version fields (numbers, which are separated by .) It works only for 32-bit PE files (as I had no need for other formats).

    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;
    }
    
    0 讨论(0)
  • 2020-12-08 11:44

    I recently moved our hosting from Windows to Linux. This was quite easy to do with VBScript given the Microsoft objects, but on Linux and PHP I couldn't find anything. We wrote this function in PHP to scan the .exe file and extract the "Product Version" that a VB.Net application had in it. You can change the $key to be whatever string you can find that has the version info and a null terminator.

    Note that this scans the files in 64k chunks looking for the $key string. If you have a large .exe, it may take a few seconds. My .exe is 52k so it is nearly instant. If you have a larger exe, you can change the scan.

    <?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");
    ?>
    
    0 讨论(0)
提交回复
热议问题