skip to Main Content

I have a Windows MSI file, that I need to programmatically read the version number from. The only place I can see this version is within the Subject of the file details:

MSI file

If I somehow can read the entire content of Subject this would be fine but is there any way to get this from PHP? The PHP is running in an IIS web server, if this helps 😉

stat is of no help for this.

I considered doing a checksum of the file, and can do that, but I really need the real version.

2

Answers


  1. Chosen as BEST ANSWER

    For now I am unable to find a native PHP solution for this, so I have temporarily solved this by calling a Powershell script as it seems easier to do in there.

    I am now having this PHP code: $version = exec("powershell.exe -file GetMsiVersion.ps1 MyFile.msi);

    With my above picture then $version will contain 1.5.9, so I will not even require to interpret the data from Subject.

    The GetMsiVersion.ps1 Powershell script has this code:

    function Get-Property ($Object, $PropertyName, [object[]]$ArgumentList) {
        return $Object.GetType().InvokeMember($PropertyName, 'Public, Instance, GetProperty', $null, $Object, $ArgumentList)
    }
    
    function Invoke-Method ($Object, $MethodName, $ArgumentList) {
        return $Object.GetType().InvokeMember($MethodName, 'Public, Instance, InvokeMethod', $null, $Object, $ArgumentList)
    }
    
    $Path = $args[0]
    $msiOpenDatabaseModeReadOnly = 0
    $Installer = New-Object -ComObject WindowsInstaller.Installer
    $Database = Invoke-Method $Installer OpenDatabase  @($Path, $msiOpenDatabaseModeReadOnly)
    $View = Invoke-Method $Database OpenView  @("SELECT Value FROM Property WHERE Property='ProductVersion'")
    Invoke-Method $View Execute
    $Record = Invoke-Method $View Fetch
    if ($Record) {
        Write-Output (Get-Property $Record StringData 1)
    }
    
    Invoke-Method $View Close @()
    

    I will accept this as the best solution here-and-now but, I hope this can be archieved natively from PHP as I see this as a better and more clean solution - and by then I will accept that as the best answer (or at least unaccept my own temporary solution).

    Doing an exec is a little evil ;-)


  2. Two things first:

    1. I have never accessed COM from PHP, but below are some VBScript samples of getting information from MSI files by using MSI API – COM automation. There are also Win32 functions.

    2. That field you refer to is not a version field, but a text field from the MSI’s "Summary Stream" – a special part of the MSI file with "meta information" of various kinds. Summary Information Stream (the full name).

    Here is how you can get the REAL version of an MSI file. This is stored in the property "ProductVersion" in the MSI file. There are at least two different ways to retrieve it – by opening the MSI file as a session or just access the property table via SQL query:

    Access version via Session object:

    Const msiUILevelNone = 2
    Dim installer : Set installer = CreateObject("WindowsInstaller.Installer")
    installer.UILevel = msiUILevelNone
    
    Set s = installer.OpenPackage("C:MySetup.msi",1)
    
    MsgBox CStr(s.ProductProperty("ProductVersion"))
    

    Accessing version via SQL agains MSI database (property table):

    Dim installer : Set installer = CreateObject("WindowsInstaller.Installer")
    
    ' Open MSI database in read-only mode (0)
    Set db = installer.OpenDatabase("C:MySetup.msi", 0)
    Set view = db.OpenView("SELECT `Value` FROM `Property` WHERE `Property`='ProductVersion'")
    view.Execute
    
    Set record = view.Fetch
    
    MsgBox CStr(record.StringData(1))
    

    Then there is the issue of accessing the SummaryStream – which is what you are really asking by the looks of it – here is a simple smoke test with some hints as to what properties you can retrieve – be careful with the summary stream – corruption is possible in various ways (I don’t recall the details, but it should be safe to access read-only):

    Dim installer : Set installer = CreateObject("WindowsInstaller.Installer")
    
    ' Open MSI database in read-only mode (0)
    Set db = installer.OpenDatabase("C:MySetup.msi", 0)
    MsgBox CStr(db.SummaryInformation.Property(3))
    
    ' 1 = "Codepage"
    ' 2 = "Title"
    ' 3 = "Subject"
    ' 4 = "Author"
    ' 5 = "Keywords"
    ' 6 = "Comments"
    ' 7 = "Template"
    ' 8 = "LastAuthor"
    ' 9 = "Revision"
    ' 11 = "Printed"
    ' 12 = "Created"
    ' 13 = "Saved"
    ' 14 = "Pages"
    ' 15 = "Words"
    ' 16 = "Characters"
    ' 18 = "Application"
    ' 19 = "Security"
    

    Links:

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search