如何解决从 PHP 读取 Windows InstallerMSI 文件属性
我有一个 Windows MSI 文件,我需要以编程方式从中读取版本号。我唯一能看到这个版本的地方是文件详细信息的主题:
如果我能以某种方式阅读 Subject 的全部内容,那就没问题了,但有什么办法可以从 PHP 中获得它吗? PHP 正在 IIS Web 服务器中运行,如果这有帮助的话 ;-)
stat
对此没有帮助。
我考虑过对文件进行校验和,并且可以做到,但我确实需要真实版本。
解决方法
首先要注意两点:
-
我从未从 PHP 访问过 COM,但以下是一些使用 MSI API - COM automation 从 MSI 文件获取信息的 VBScript 示例。 There are also Win32 functions。
-
您所指的那个字段不是版本字段,而是来自 MSI 的“摘要流”的文本字段——MSI 文件的一个特殊部分,带有各种“元信息”。 Summary Information Stream(全名)。
以下是获取真实版本的 MSI 文件的方法。这存储在 MSI 文件的属性 "ProductVersion"
中。至少有两种不同的方法可以检索它 - 通过将 MSI 文件作为会话打开或仅通过 SQL 查询访问属性表:
通过会话对象访问版本:
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 解决方案,因此我通过调用 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,InvokeMethod',$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
有点邪恶;-)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。