【问题标题】:Read Windows Installer (MSI file) attributes from PHP从 PHP 读取 Windows 安装程序(MSI 文件)属性
【发布时间】:2022-01-12 03:37:23
【问题描述】:

我有一个 Windows MSI 文件,我需要以编程方式从中读取版本号。我唯一能看到这个版本的地方是文件详细信息的主题

如果我能以某种方式阅读 Subject 的全部内容,那就没问题了,但是有什么方法可以从 PHP 中获取? PHP 正在 IIS Web 服务器中运行,如果这有帮助的话 ;-)

stat 对此无济于事。

我考虑过对文件进行校验和,并且可以这样做,但我真的需要真实版本。

【问题讨论】:

    标签: php windows-installer


    【解决方案1】:

    目前我无法为此找到原生 PHP 解决方案,因此我通过调用 Powershell 脚本暂时解决了这个问题,因为在那里看起来更容易做到。

    我现在有这个 PHP 代码: $version = exec("powershell.exe -file GetMsiVersion.ps1 MyFile.msi);

    根据我上面的图片,$version 将包含1.5.9,所以我什至不需要解释来自 Subject 的数据。

    GetMsiVersion.ps1 Powershell 脚本有这样的代码:

    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 @()
    

    我现在会接受这是最好的解决方案,但是,我希望这可以从 PHP 本地归档,因为我认为这是一个更好、更干净的解决方案 - 到那时我会接受它作为最佳答案(或者至少不接受我自己的临时解决方案)。

    exec 有点邪恶 ;-)

    【讨论】:

      【解决方案2】:

      先做两件事:

      1. 我从未从 PHP 访问过 COM,但下面是一些使用 MSI API - COM automation 从 MSI 文件中获取信息的 VBScript 示例。 There are also Win32 functions.

      2. 您指的那个字段不是版本字段,而是来自 MSI 的“摘要流”的文本字段 - MSI 文件的特殊部分,带有各种“元信息”。 Summary Information Stream(全名)。

      以下是获取 MSI 文件真实版本的方法。这存储在 MSI 文件的属性 "ProductVersion" 中。至少有两种不同的方法来检索它 - 通过将 MSI 文件作为会话打开或仅通过 SQL 查询访问属性表:

      通过 Session 对象访问版本:

      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"))
      

      通过 SQL 访问 MSI 数据库(属性表)的版本:

      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))
      

      然后是访问 SummaryStream 的问题 - 从外观上看,这是您真正要问的问题 - 这是一个简单的冒烟测试,其中包含一些关于您可以检索哪些属性的提示 - 小心摘要流 -损坏可能有多种方式(我不记得细节,但以只读方式访问应该是安全的):

      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"
      

      链接:

      【讨论】:

      • 感谢您提供详细信息,但我很遗憾地说,它并没有让我更接近原生 PHP 解决方案,因为我无法将您的 VBScript 建议转换为 PHP ;-)
      猜你喜欢
      • 2018-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多