Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/workflows/hooks-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Test Plugin

on:
pull_request:
push:
branches: [main]

permissions:
contents: read

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version: '1.24.0'
cache: false
- name: Test plugin hooks with vfox's Lua interpreter
run: go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/hooks_test.lua
- name: Test Windows configuration generation
run: go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/windows_test.lua
- name: Test macOS OpenSSL selection
run: bash tests/openssl_test.sh
11 changes: 9 additions & 2 deletions .github/workflows/test-linux.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ name: Test linux workflow
on:
pull_request:
push:
branches: [main]
workflow_dispatch:
schedule:
- cron: 0 0 * * 5

Expand All @@ -15,7 +17,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: install vfox (Linux)
run: |
echo "deb [trusted=yes] https://apt.fury.io/versionfox/ /" | sudo tee /etc/apt/sources.list.d/versionfox.list
Expand All @@ -30,11 +32,16 @@ jobs:
zip -r php.zip ./

- name: Test
env:
MAKEFLAGS: -j2
run: |
vfox add -s php.zip
vfox install php@latest
vfox use -p php@$(vfox list php | sed -n 's/-> v//p')
eval "$(vfox activate bash)"
vfox use -p php@latest
eval "$(vfox env --shell bash)"
php_path=$(command -v php)
[[ "$php_path" == "$(pwd -P)/.vfox/sdks/php/bin/php" ]]
php -v
php -m
composer -V
13 changes: 10 additions & 3 deletions .github/workflows/test-macos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ name: Test macos workflow
on:
pull_request:
push:
branches: [main]
workflow_dispatch:
schedule:
- cron: 0 0 * * 5

Expand All @@ -15,7 +17,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: install vfox (MacOS)
run: |
brew tap version-fox/tap
Expand All @@ -26,15 +28,20 @@ jobs:
zip -r php.zip ./

- name: Install packages
run: brew install autoconf automake bison freetype gd gettext icu4c krb5 libedit libiconv libjpeg libpng libxml2 libxslt libzip pkg-config re2c zlib
run: brew install autoconf automake bison freetype gd gettext icu4c krb5 libedit libiconv libjpeg libpng libxml2 libxslt libzip openssl@3 pkg-config re2c zlib

- name: Test
env:
MAKEFLAGS: -j2
shell: bash
run: |
vfox add -s php.zip
vfox install php@latest
vfox use -p php@$(vfox list php | sed -n 's/-> v//p')
eval "$(vfox activate bash)"
vfox use -p php@latest
eval "$(vfox env --shell bash)"
php_path=$(command -v php)
[[ "$php_path" == "$(pwd -P)/.vfox/sdks/php/bin/php" ]]
php -v
php -m
composer -V
8 changes: 6 additions & 2 deletions .github/workflows/test-windows.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ name: Test windows workflow
on:
pull_request:
push:
branches: [main]
workflow_dispatch:
schedule:
- cron: 0 0 * * 5

Expand All @@ -15,20 +17,22 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: install vfox and test (Windows)
shell: pwsh
run: |
$PSNativeCommandUseErrorActionPreference = $true
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression
scoop install vfox
Compress-Archive -Path .\* -DestinationPath .\php.zip
vfox -v
vfox add -s php.zip
vfox install php@latest
vfox use -p php@$(vfox list php | sed -n 's/-> v//p')
vfox use -p php@latest
Invoke-Expression "$(vfox activate pwsh)"
php -v
php -m
if (-not ((php -m) -contains "openssl")) { throw "OpenSSL extension was not loaded" }
composer -V
Empty file removed .tool-versions
Empty file.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ vfox install php@8.4.5
vfox install php@8.4.5-nts
```

The version list combines current and archived Windows binaries, sorted newest
first. Plain Windows versions select thread-safe (TS) builds; `-nts` selects NTS.
Linux and macOS source versions come directly from PHP's official JSON API.
Network failures report the upstream URL instead of returning an empty list.

## Prerequirements

PHP installation requires some dependencies. Please install the dependencies based on the error messages, or refer to [.github/workflows/test-\*.yaml](https://github.com/version-fox/vfox-php/tree/main/.github/workflows) for guidance.
Expand All @@ -26,9 +31,17 @@ PHP installation requires some dependencies. Please install the dependencies bas
To install PHP on macOS, you'll need a set of packages installed via homebrew.

```shell
brew install autoconf automake bison freetype gd gettext icu4c krb5 libedit libiconv libjpeg libpng libxml2 libzip pkg-config re2c zlib
brew install autoconf automake bison freetype gd gettext icu4c krb5 libedit libiconv libjpeg libpng libxml2 libzip openssl@3 pkg-config re2c zlib
```

PHP 8.1 and newer use `openssl@3` on macOS. Older PHP versions require a
compatible older OpenSSL installation; the build reports a missing dependency
instead of silently selecting OpenSSL 3 or omitting HTTPS support. Homebrew no
longer supplies `openssl@1.1` through its normal supported formulae. See the
[PHP OpenSSL compatibility requirements](https://www.php.net/manual/en/openssl.requirements.php).
If you supply `PHP_CONFIGURE_OPTIONS`, you remain responsible for configuring
the dependency paths; automatic macOS dependency selection is bypassed.

There's also a set of optional packages which enable additional extensions to be enabled:

```shell
Expand Down
45 changes: 39 additions & 6 deletions bin/install
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ install_php() {
local install_path=$1

local source_path="${install_path}_source"
local configure_options="$(construct_configure_options $install_path)"
local configure_options
configure_options="$(construct_configure_options "$install_path")" || return 1

local operating_system=$(uname -a)

Expand All @@ -20,7 +21,11 @@ install_php() {
local libedit_path=$(homebrew_package_path libedit)
local libxml2_path=$(homebrew_package_path libxml2)
local libxslt_path=$(homebrew_package_path libxslt)
local openssl_path=$(homebrew_package_path openssl@1.1)
local openssl_path
# Explicit configure options own their dependency paths, as before.
if [ -z "${PHP_CONFIGURE_OPTIONS:-}" ]; then
openssl_path=$(homebrew_openssl_path) || return 1
fi

if [ -n "$bison_path" ]; then
export "PATH=${bison_path}/bin:${PATH}"
Expand Down Expand Up @@ -133,7 +138,9 @@ construct_configure_options() {
--without-snmp"

if [ "$PHP_CONFIGURE_OPTIONS" = "" ]; then
local configure_options="$(os_based_configure_options) $global_config"
local platform_options
platform_options=$(os_based_configure_options) || return 1
local configure_options="$platform_options $global_config"
else
local configure_options="$PHP_CONFIGURE_OPTIONS $global_config"
fi
Expand Down Expand Up @@ -163,6 +170,28 @@ homebrew_package_path() {
fi
}

homebrew_openssl_path() {
# PHP 7.1-8.0 requires OpenSSL < 3.0; PHP 8.1+ supports OpenSSL 3.
# See https://www.php.net/manual/en/openssl.requirements.php
local major minor formula path
if [[ ! "${PHP_VERSION:-}" =~ ^([0-9]+)\.([0-9]+)\. ]]; then
echo "ERROR: Cannot determine PHP version for OpenSSL selection" >&2
return 1
fi
major=${BASH_REMATCH[1]}
minor=${BASH_REMATCH[2]}
formula=openssl@1.1
if (( major > 8 || (major == 8 && minor >= 1) )); then
formula=openssl@3
fi
path=$(homebrew_package_path "$formula")
if [ -z "$path" ]; then
echo "ERROR: PHP $PHP_VERSION requires $formula; install a compatible dependency before building." >&2
return 1
fi
echo "$path"
}

exit_if_homebrew_not_installed() {
if [ "$(brew --version 2>/dev/null)" = "" ]; then
echo "ERROR: Please install homebrew for OSX"
Expand Down Expand Up @@ -190,7 +219,8 @@ os_based_configure_options() {
local libxml2_path=$(homebrew_package_path libxml2)
local libxslt_path=$(homebrew_package_path libxslt)
local libzip_path=$(homebrew_package_path libzip)
local openssl_path=$(homebrew_package_path openssl@1.1)
local openssl_path
openssl_path=$(homebrew_openssl_path) || return 1
local readline_path=$(homebrew_package_path readline)
local webp_path=$(homebrew_package_path webp)
local zlib_path=$(homebrew_package_path zlib)
Expand Down Expand Up @@ -298,5 +328,8 @@ os_based_configure_options() {
echo $configure_options
}

install_php $1
install_composer $1
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
PHP_VERSION=${2:-$(sed -n 's/^#define PHP_VERSION "\([^"]*\)"/\1/p' "$1/main/php_version.h")}
install_php "$1"
install_composer "$1"
fi
81 changes: 2 additions & 79 deletions hooks/available.lua
Original file line number Diff line number Diff line change
@@ -1,82 +1,5 @@
local http = require('http')
local html = require('html')
local util = require('util')
require('constants')
local releases = require("releases")

--- Return all available versions provided by this plugin
--- @param ctx table Empty table used as context, for future extension
--- @return table Descriptions of available versions and accompanying tool descriptions
function PLUGIN:Available(ctx)
if RUNTIME.osType == 'windows' then
return GetReleaseListForWindows()
else
return GetReleaseListForLinux()
end
end

function GetReleaseListForWindows()
local result = {}
local urls = { WIN_RELEASES_URL, WIN_RELEASES_URL_LTS }

for _, url in ipairs(urls) do
local resp, err = http.get({ url = url })

if resp then
local doc = html.parse(resp.body)
local versions = {}
doc:find('a'):each(function(i, selection)
local versionStr = selection:text()
table.insert(versions, versionStr)
end)
-- TODO like this because for some reason sorting it at the end resets is_from_lts to false
table.sort(versions, function(a, b)
return util.compare_versions(a, b) > 0
end)
for _, versionStr in ipairs(versions) do
if util.filter_windows_version(versionStr) then
local versions = util.split_string(versionStr, '-')
if util.compare_versions(versions[2], "5.3.2") >= 0 then
local entry = {
version = (versions[3] ~= "nts") and versions[2] or versions[2] .. "-nts",
name = versionStr
}

entry.is_from_lts = (url == WIN_RELEASES_URL_LTS)
table.insert(result, entry)
end
end
end
end
end

return result
end

function GetReleaseListForLinux()
local result = {}
local urls = { RELEASES_URL, RELEASES_URL_LTS }

for _, url in ipairs(urls) do
local resp, err = http.get({ url = url })
local is_from_lts = (url == RELEASES_URL_LTS)

if resp then
local doc = html.parse(resp.body)
local query = "#layout-content " .. (is_from_lts and "h3" or "h2")
doc:find(query):each(function(i, selection)
local versionStr = is_from_lts and selection:attr("id") or selection:text()
versionStr = versionStr:gsub("^v", "")
if util.compare_versions(versionStr, "5.3.2") >= 0 then
table.insert(result, {
version = versionStr,
})
end
end)
end
end

table.sort(result, function(a, b)
return util.compare_versions(a.version, b.version) > 0
end)
return result
return releases.available()
end
18 changes: 14 additions & 4 deletions hooks/post_install.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function PLUGIN:PostInstall(ctx)
if RUNTIME.osType == 'windows' then
InstallComposerForWin(path)
else
CompileInstallPHP(path)
CompileInstallPHP(path, sdkInfo.version)
end
end

Expand All @@ -19,7 +19,14 @@ function InstallComposerForWin(path)
if err ~= nil then
error(err)
end
content = content:gsub(';%s*extension_dir = "ext"', 'extension_dir = "./ext"')
-- Use an absolute extension_dir so php.exe can locate php_openssl.dll
-- regardless of which CWD it was launched from. The composer-setup
-- step below invokes php.exe from the user's shell CWD, so a relative
-- "./ext" path resolves to the wrong directory and fails to load
-- openssl, breaking the HTTPS download Composer needs.
local ext_dir = (path .. "\\ext"):gsub("\\", "/")
content = content:gsub(';%s*extension_dir = "ext"',
function() return 'extension_dir = "' .. ext_dir .. '"' end)
content = content:gsub(';extension=openssl', 'extension=openssl')
content = content:gsub(';extension=php_openssl.dll', 'extension=php_openssl.dll')
_, err = util.write_file(path .. '\\php.ini', content)
Expand Down Expand Up @@ -68,9 +75,12 @@ function InstallComposerForWin(path)
util.write_file(path .. '\\composer.bat', '@php "%~dp0composer.phar" %*')
end

function CompileInstallPHP(path)
function CompileInstallPHP(path, version)
if not version:match("^%d+%.%d+%.%d+$") then
error("Invalid PHP source version: " .. tostring(version))
end
os.execute('chmod +x ' .. RUNTIME.pluginDirPath .. '/bin/install')
local code = os.execute(RUNTIME.pluginDirPath .. '/bin/install ' .. path)
local code = os.execute(RUNTIME.pluginDirPath .. '/bin/install ' .. path .. ' ' .. version)
if code ~= 0 then
error('Compilation Failure.')
end
Expand Down
Loading
Loading