diff --git a/PhpManager/PhpManager.psd1 b/PhpManager/PhpManager.psd1 index e416bea..fca7f61 100644 --- a/PhpManager/PhpManager.psd1 +++ b/PhpManager/PhpManager.psd1 @@ -19,7 +19,7 @@ # TypesToProcess = @() # FormatsToProcess = @() # NestedModules = @() - FunctionsToExport = 'Get-PhpAvailableVersion', 'Install-Php', 'Update-Php', 'Uninstall-Php', 'Get-Php', 'Set-PhpIniKey', 'Get-PhpIniKey', 'Get-PhpExtension', 'Enable-PhpExtension', 'Disable-PhpExtension', 'Install-PhpExtension', 'Update-PhpCAInfo', 'Set-PhpDownloadCache', 'Get-PhpDownloadCache', 'Initialize-PhpSwitcher', 'Add-PhpToSwitcher', 'Get-PhpSwitcher', 'Remove-PhpFromSwitcher', 'Switch-Php', 'Move-PhpSwitcher', 'Remove-PhpSwitcher', 'Install-Composer' + FunctionsToExport = 'Get-PhpAvailableVersion', 'Install-Php', 'Update-Php', 'Uninstall-Php', 'Get-Php', 'Set-PhpIniKey', 'Get-PhpIniKey', 'Get-PhpExtension', 'Enable-PhpExtension', 'Disable-PhpExtension', 'Install-PhpExtension', 'Install-PhpExtensionPrerequisite', 'Update-PhpCAInfo', 'Set-PhpDownloadCache', 'Get-PhpDownloadCache', 'Initialize-PhpSwitcher', 'Add-PhpToSwitcher', 'Get-PhpSwitcher', 'Remove-PhpFromSwitcher', 'Switch-Php', 'Move-PhpSwitcher', 'Remove-PhpSwitcher', 'Install-Composer' CmdletsToExport = '' VariablesToExport = '' AliasesToExport = '' diff --git a/PhpManager/private/Install-ImagickPrerequisite.ps1 b/PhpManager/private/Install-ImagickPrerequisite.ps1 new file mode 100644 index 0000000..850185e --- /dev/null +++ b/PhpManager/private/Install-ImagickPrerequisite.ps1 @@ -0,0 +1,80 @@ +function Install-ImagickPrerequisite() { + <# + .Synopsis + Installs the prerequisites for the imagick PHP extension. + + .Parameter PhpVersion + The PhpVersion instance the extension will be installed for. + + .Parameter InstallPath + The path to a directory where the prerequisites should be installed. + #> + [OutputType()] + param ( + [Parameter(Mandatory = $true, Position = 0)] + [ValidateNotNull()] + [PhpVersionInstalled] $PhpVersion, + [Parameter(Mandatory = $true, Position = 1)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] $InstallPath + ) + begin { + } + process { + $rxSearch = '/ImageMagick-[\d\.\-]+-(VC|vc|vs)' + $PhpVersion.VCVersion + '-' + $PhpVersion.Architecture + '\.zip$' + $pageUrl = 'https://windows.php.net/downloads/pecl/deps/' + Set-NetSecurityProtocolType + $webResponse = Invoke-WebRequest -UseBasicParsing -Uri $pageUrl + $zipUrl = $null + foreach ($link in $webResponse.Links) { + $fullUrl = [Uri]::new([Uri]$pageUrl, $link.Href).AbsoluteUri + if ($fullUrl -match $rxSearch) { + $zipUrl = $fullUrl + break + } + } + if ($null -eq $zipUrl) { + throw ('Unable to find the imagick package dependencies on {0} for {1}' -f $pageUrl, $PhpVersion.DisplayName) + } + Write-Verbose "Downloading and extracting $zipUrl" + $zipFile, $keepZipFile = Get-FileFromUrlOrCache -Url $zipUrl + try { + $tempFolder = New-TempDirectory + try { + try { + Expand-ArchiveWith7Zip -ArchivePath $zipFile -DestinationPath $tempFolder + } catch { + $keepZipFile = $false + throw + } + $items = Get-ChildItem -LiteralPath $tempFolder -Recurse -File -Filter *.dll ` | Where-Object { $_.Name -like 'CORE_RL_*.dll' -or $_.Name -like 'IM_MOD_RL_*.dll' } + foreach ($item in $items) { + $destinationPath = [System.IO.Path]::Combine($InstallPath, $item.Name) + Move-Item -LiteralPath $item.FullName -Destination $destinationPath -Force + try { + Reset-Acl -Path $destinationPath + } catch { + Write-Debug -Message "Failed to reset the ACL for $($destinationPath): $($_.Exception.Message)" + } + } + } finally { + try { + Remove-Item -Path $tempFolder -Recurse -Force + } catch { + Write-Debug 'Failed to remove temporary folder' + } + } + } finally { + if (-Not($keepZipFile)) { + try { + Remove-Item -Path $zipFile + } catch { + Write-Debug 'Failed to remove temporary zip file' + } + } + } + } + end { + } +} diff --git a/PhpManager/private/Install-PhpExtensionPrerequisite.ps1 b/PhpManager/private/Install-PhpExtensionPrerequisite.ps1 deleted file mode 100644 index 29f323b..0000000 --- a/PhpManager/private/Install-PhpExtensionPrerequisite.ps1 +++ /dev/null @@ -1,85 +0,0 @@ -function Install-PhpExtensionPrerequisite() { - <# - .Synopsis - Installs the prerequisites of a PHP extension. - - .Parameter PhpVersion - The PhpVersion instance the extension will be installed for. - - .Parameter Extension - The PhpExtension instance representing the extension. - #> - [OutputType()] - param ( - [Parameter(Mandatory = $true, Position = 0)] - [ValidateNotNull()] - [PhpVersionInstalled] $PhpVersion, - [Parameter(Mandatory = $true, Position = 1)] - [ValidateNotNull()] - [PhpExtension] $Extension - ) - begin { - } - process { - Write-Verbose ('Checking prerequisites for {0}' -f $Extension.Name) - switch ($Extension.Handle) { - imagick { - $rxSearch = '/ImageMagick-[\d\.\-]+-(VC|vc|vs)' + $PhpVersion.VCVersion + '-' + $PhpVersion.Architecture + '\.zip$' - $pageUrl = 'https://windows.php.net/downloads/pecl/deps/' - Set-NetSecurityProtocolType - $webResponse = Invoke-WebRequest -UseBasicParsing -Uri $pageUrl - $zipUrl = $null - foreach ($link in $webResponse.Links) { - $fullUrl = [Uri]::new([Uri]$pageUrl, $link.Href).AbsoluteUri - if ($fullUrl -match $rxSearch) { - $zipUrl = $fullUrl - break - } - } - if ($null -eq $zipUrl) { - throw ('Unable to find the imagick package dependencies on {0} for {1}' -f $pageUrl, $PhpVersion.DisplayName) - } - Write-Verbose "Downloading and extracting $zipUrl" - $zipFile, $keepZipFile = Get-FileFromUrlOrCache -Url $zipUrl - try { - $tempFolder = New-TempDirectory - try { - try { - Expand-ArchiveWith7Zip -ArchivePath $zipFile -DestinationPath $tempFolder - } catch { - $keepZipFile = $false - throw - } - $items = Get-ChildItem -LiteralPath $tempFolder -Recurse -File -Filter *.dll ` - | Where-Object { $_.Name -like 'CORE_RL_*.dll' -or $_.Name -like 'IM_MOD_RL_*.dll' } - foreach ($item in $items) { - $destinationPath = [System.IO.Path]::Combine($PhpVersion.ActualFolder, $item.Name) - Move-Item -LiteralPath $item.FullName -Destination $destinationPath -Force - try { - Reset-Acl -Path $destinationPath - } catch { - Write-Debug -Message "Failed to reset the ACL for $($destinationPath): $($_.Exception.Message)" - } - } - } finally { - try { - Remove-Item -Path $tempFolder -Recurse -Force - } catch { - Write-Debug 'Failed to remove temporary folder' - } - } - } finally { - if (-Not($keepZipFile)) { - try { - Remove-Item -Path $zipFile - } catch { - Write-Debug 'Failed to remove temporary zip file' - } - } - } - } - } - } - end { - } -} diff --git a/PhpManager/public/Install-PhpExtension.ps1 b/PhpManager/public/Install-PhpExtension.ps1 index 251e5c5..aaa6110 100644 --- a/PhpManager/public/Install-PhpExtension.ps1 +++ b/PhpManager/public/Install-PhpExtension.ps1 @@ -24,6 +24,9 @@ .Parameter Path The path of the PHP installation. If omitted we'll use the one found in the PATH environment variable. + + .Parameter NoDependncies + Skip the installation of extension dependencies (youl'll have to manually call Install-PhpExtensionPrerequisite before calling Install-PhpExtension). #> [OutputType()] param ( @@ -47,7 +50,8 @@ [ValidateNotNull()] [ValidateLength(1, [int]::MaxValue)] [string] $Path, - [switch] $DontEnable + [switch] $DontEnable, + [switch] $NoDependncies ) begin { } @@ -222,7 +226,9 @@ } else { Write-Verbose ("Installing new extension '{0}' version {1}" -f $newExtension.Name, $newExtension.Version) - Install-PhpExtensionPrerequisite -PhpVersion $phpVersion -Extension $newExtension + if (-not($NoDependncies)) { + Install-PhpExtensionPrerequisite -Extension $newExtension.Handle -PhpPath $phpVersion.ActualFolder + } if ($null -eq $finalDllName) { $newExtensionFilename = [System.IO.Path]::Combine($phpVersion.ExtensionsPath, [System.IO.Path]::GetFileName($dllPath)) } else { diff --git a/PhpManager/public/Install-PhpExtensionPrerequisite.ps1 b/PhpManager/public/Install-PhpExtensionPrerequisite.ps1 new file mode 100644 index 0000000..6569d3f --- /dev/null +++ b/PhpManager/public/Install-PhpExtensionPrerequisite.ps1 @@ -0,0 +1,64 @@ +function Install-PhpExtensionPrerequisite() { + <# + .Synopsis + Installs the prerequisites of PHP extensions. + + .Parameter Extension + The name (or the handle) of the PHP extension(s) to be disabled. + + .Parameter InstallPath + The path to a directory where the prerequisites should be installed (it should be in your PATH environment variable). + If omitted we'll install the dependencies in the PHP directory. + + .Parameter PhpPath + The path to the PHP installation. + If omitted we'll use the one found in the PATH environment variable. + + .Example + Install-PhpExtensionPrerequisite imagick,zip + #> + [OutputType()] + param ( + [Parameter(Mandatory = $true, Position = 0, HelpMessage = 'The name (or the handle) of the PHP extension(s) to be disabled')] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string[]] $Extension, + [Parameter(Mandatory = $false, Position = 1, HelpMessage = 'The path to a directory where the prerequisites should be installed (it should be in your PATH environment variable); if omitted we''ll install the dependencies in the PHP directory')] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] $InstallPath, + [Parameter(Mandatory = $false, Position = 2, HelpMessage = 'The path to the PHP installation; if omitted we''ll use the one found in the PATH environment variable')] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] $PhpPath + ) + begin { + } + process { + if ($null -eq $PhpPath -or $PhpPath -eq '') { + $phpVersion = [PhpVersionInstalled]::FromEnvironmentOne() + Write-Verbose "Using PHP found in $($phpVersion.ActualFolder)" + } else { + $phpVersion = [PhpVersionInstalled]::FromPath($Path) + } + if ($null -eq $InstallPath -or $InstallPath -eq '') { + $InstallPath = $phpVersion.ActualFolder + } elseif (-not(Test-Path -LiteralPath $InstallPath -PathType Container)) { + throw "The directory $InstallPath does not exist" + } + foreach ($wantedExtension in $Extension) { + $wantedExtensionHandle = Get-PhpExtensionHandle -Name $wantedExtension + Write-Verbose "Checking prerequisites for $wantedExtensionHandle" + switch ($wantedExtensionHandle) { + imagick { + Install-ImagickPrerequisite -PhpVersion $phpVersion -InstallPath $InstallPath + } + default { + Write-Verbose "No prerequisites needed for $wantedExtensionHandle" + } + } + } + } + end { + } +} diff --git a/README.md b/README.md index be773db..7b46dff 100644 --- a/README.md +++ b/README.md @@ -262,6 +262,10 @@ Install-PhpExtension xdebug -Version 2.6 Install-PhpExtension imagick -MinimumStability snapshot ``` +Some extensions require additional dependencies (for example `imagick`). +By default, `Install-PhpExtension` automatically installs these dependencies in the directory where PHP is installed. +If you want to install them in another directory, you have to call the `Install-PhpExtensionPrerequisite` command, and specify the `-NoDependncies` option for `Install-PhpExtension`. + PS: `Install-PhpExtension` can also be used to upgrade (or downgrade) a PHP extension to the most recent version available online. ### Getting the list of PHP versions available online