diff --git a/src/configs/pie-extensions.json b/src/configs/pie-extensions.json new file mode 100644 index 00000000..02319bde --- /dev/null +++ b/src/configs/pie-extensions.json @@ -0,0 +1,111 @@ +{ + "amqp": "php-amqp/php-amqp", + "apcu": "apcu/apcu", + "apfd": "m6w6/ext-apfd", + "arrow": "flow-php/arrow-ext", + "ast": "nikic/php-ast", + "biscuit_php": "ptondereau/biscuit-php", + "bitset": "pecl/bitset", + "brotli": "kjdev/brotli", + "bsdiff": "bsdiff/bsdiff", + "csv": "girgias/csv", + "dbus": "pecl/dbus", + "decimal": "php-decimal/ext-decimal", + "deepclone": "symfony/deepclone", + "dio": "pecl/dio", + "ds": "php-ds/ext-ds", + "ev": "osmanov/pecl-ev", + "event": "osmanov/pecl-event", + "excel": "iliaal/php-excel", + "excimer": "wikimedia/excimer", + "fast_uuid": "iliaal/fast_uuid", + "fastchart": "iliaal/fastchart", + "fastjson": "iliaal/fastjson", + "geospatial": "php-geospatial/geospatial", + "glfw": "mario-deluna/php-glfw", + "grpc": "grpc/grpc-php-ext", + "hdr_histogram": "beberlei/hdrhistogram", + "hdrhistogram": "beberlei/hdrhistogram", + "highlighter": "yiipress/highlighter", + "http": "m6w6/ext-http", + "igbinary": "igbinary/igbinary", + "imagick": "imagick/imagick", + "inotify": "arnaud-lb/inotify", + "ip2location": "ip2location/ip2location-pie", + "ip2proxy": "ip2location/ip2proxy-pie", + "json_post": "m6w6/ext-json_post", + "jsonpath": "supermetrics/jsonpath", + "judy": "orieg/judy", + "krb5": "pecl/krb5", + "lchash": "iliaal/lchash", + "luasandbox": "wikimedia/luasandbox", + "lz4": "kjdev/lz4", + "lzf": "pecl/lzf", + "mailparse": "pecl/mailparse", + "maxminddb": "maxmind-db/reader-ext", + "mcrypt": "pecl/mcrypt", + "mdparser": "iliaal/mdparser", + "memcached": "php-memcached/php-memcached", + "memprof": "arnaud-lb/memprof", + "mjml": "kcs/mjml", + "mongodb": "mongodb/mongodb-extension", + "msgpack": "msgpack/msgpack-php", + "mustache": "jbboehr/php-mustache", + "oci8": "oci8/oci8", + "openswoole": "openswoole/ext-openswoole", + "opentelemetry": "open-telemetry/ext-opentelemetry", + "operator": "jblo/operator", + "parallel": "pecl/parallel", + "pcov": "pecl/pcov", + "pdo_duckdb": "thomas-0816/pdo-duckdb-php", + "pdo_oci": "pecl/pdo_oci", + "pdo_sqlsrv": "microsoft/pdo_sqlsrv", + "pecl_http": "m6w6/ext-http", + "phalcon": "phalcon/cphalcon", + "phonetic": "iliaal/phonetic", + "phpser": "iliaal/phpser", + "phpstan_turbo": "phpstan/turbo", + "pkcs11": "gamringer/pkcs11", + "pq": "m6w6/ext-pq", + "quickhash": "derickr/quickhash", + "raphf": "m6w6/ext-raphf", + "rar": "cataphract/rar", + "rdkafka": "rdkafka/rdkafka", + "redis": "phpredis/phpredis", + "relay": "cachewerk/ext-relay", + "rpminfo": "remi/rpminfo", + "scrypt": "woohoolabs/php-scrypt", + "selinux": "pecl/selinux", + "snappy": "kjdev/snappy", + "solr": "pecl/solr", + "spx": "noisebynorthwest/php-spx", + "sqlsrv": "microsoft/sqlsrv", + "statgrab": "iliaal/statgrab", + "swoole": "swoole/swoole", + "swow": "swow/swow-extension", + "taint": "laruence/taint", + "tensor": "rubix/tensor_ext", + "timezonedb": "pecl/timezonedb", + "translit": "derickr/translit", + "uopz": "krakjoe/uopz", + "uuid": "pecl/uuid", + "uv": "amphp/uv", + "valkey_glide": "valkey-io/valkey-glide-php", + "vld": "derickr/vld", + "wikidiff2": "wikimedia/wikidiff2", + "win32service": "win32service/win32service", + "xattr": "pecl/xattr", + "xdebug": "xdebug/xdebug", + "xdiff": "pecl/xdiff", + "xlswriter": "viest/xlswriter", + "xmldiff": "pecl/xml-xmldiff", + "xpass": "remi/xpass", + "yac": "laruence/yac", + "yaconf": "laruence/yaconf", + "yaf": "laruence/yaf", + "yaml": "pecl/yaml", + "yar": "laruence/yar", + "yaz": "indexdata/yaz", + "zip": "pecl/zip", + "zstd": "kjdev/zstd" +} diff --git a/src/scripts/extensions/add_extensions.ps1 b/src/scripts/extensions/add_extensions.ps1 index 60cec0fe..57d9210b 100644 --- a/src/scripts/extensions/add_extensions.ps1 +++ b/src/scripts/extensions/add_extensions.ps1 @@ -85,6 +85,67 @@ Function Add-ExtensionFromGithub { } } +# Function to install a PIE package or mapped version. Windows uses prebuilt DLLs. +Function Add-PieExtension { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [string] + $extension, + [Parameter(Position = 1, Mandatory = $false)] + [string] + $package = '', + [Parameter(Position = 2, Mandatory = $false)] + [Alias('AllowSourceBuild')] + [bool] + $allow_source = $false + ) + $requested = ($package -split ':', 2)[-1] + if ($package -notmatch '/') { + $mapping = Get-Content "$src\configs\pie-extensions.json" -Raw | ConvertFrom-Json + $package = $mapping.$extension + if (-not $package) { throw "No PIE package mapping for $extension" } + if ($requested -in @('', 'latest', 'stable')) { $requested = '' } else { $package += ":$requested" } + } elseif ($package -notmatch ':') { + $requested = '' + } + & "$php_dir\php.exe" -r 'exit(extension_loaded($argv[1]) && ($argv[2] === "" || phpversion($argv[1]) === $argv[2]) ? 0 : 1);' -- $extension "$requested" >$null 2>&1 + if ($LASTEXITCODE -eq 0) { + Add-Log $tick $extension 'Enabled' + return + } + $pie_args = @('install', $package, '--no-interaction', '--skip-enable-extension', '--no-build-tools-check', '--no-system-dependencies-check', "--with-php-path=$php_dir\php.exe") + if (-not $allow_source) { + # Skip CPU detection when compilation is disabled. + $pie_args += @('--suppress-download-url-method=composer-default', '--suppress-download-url-method=pre-packaged-source', '--make-parallel-jobs=1') + } + New-Item -ItemType Directory -Path $composer_home -Force >$null + Set-ComposerAuth + $pie_log = Join-Path ([System.IO.Path]::GetTempPath()) "pie-$extension.log" + $pie_path = Join-Path $bin_dir 'pie' + if ([version]$installed.MajorMinorVersion -lt [version]'8.1') { + $pie_path = Join-Path $bin_dir 'pie-cli.exe' + if (-not (Test-Path $pie_path -PathType Leaf)) { + Get-File -Url https://github.com/php/pie/releases/latest/download/pie-Windows-X64.exe -OutFile $pie_path + } + & $pie_path @pie_args >$pie_log 2>&1 + } else { + if (-not (Test-Path $pie_path -PathType Leaf)) { + Add-Tool https://github.com/php/pie/releases/latest/download/pie.phar pie '-V' >$null 2>&1 + } + & "$php_dir\php.exe" $pie_path @pie_args >$pie_log 2>&1 + } + if ($LASTEXITCODE -ne 0) { + Get-Content $pie_log | ForEach-Object { Write-Host $_ } + throw "Could not install $package using PIE (exit code $LASTEXITCODE)" + } + Enable-ExtensionDependencies $extension + Enable-PhpExtension -Extension $extension -Path $php_dir + & "$php_dir\php.exe" -r 'exit(extension_loaded($argv[1]) ? 0 : 1);' -- $extension >$null 2>&1 + if ($LASTEXITCODE -ne 0) { throw "Could not load $extension after installing $package using PIE" } + Add-Log $tick $extension 'Installed and enabled' +} + # Function to add PHP extensions. Function Add-Extension { Param ( diff --git a/src/scripts/extensions/add_extensions.sh b/src/scripts/extensions/add_extensions.sh index 963a9e74..0a149c72 100644 --- a/src/scripts/extensions/add_extensions.sh +++ b/src/scripts/extensions/add_extensions.sh @@ -188,6 +188,54 @@ get_pecl_version() { echo "$response" | grep -Eio "$pattern" | head -n 1 | cut -d '>' -f 2 | cut -d '<' -f 1 } +# Install a PIE package or mapped version: extension, package, allow_source=false, prefix. +pie_install() { + local extension=$1 package=${2:-} allow_source=${3:-false} + local prefix=${4:-$(get_extension_prefix "$extension")} requested pie_path php_config asset arch + requested=${package##*:} + if [[ "$package" != */* ]]; then + package=$(jq -er --arg extension "$extension" '.[$extension]' "${src:?}/configs/pie-extensions.json") || return 1 + case "$requested" in ''|latest|stable) requested= ;; *) package="$package:$requested" ;; esac + elif [[ "$package" != *:* ]]; then + requested= + fi + if php -d display_errors=0 -r 'exit(extension_loaded($argv[1]) && ($argv[2] === "" || phpversion($argv[1]) === $argv[2]) ? 0 : 1);' -- "$extension" "$requested"; then + return 0 + fi + local pie_args=(install "$package" --no-interaction --skip-enable-extension --no-build-tools-check --no-system-dependencies-check) + php_config=$(command -v php-config) || return 1 + pie_args+=("--with-php-config=$php_config") + if [ "$allow_source" != true ]; then + # Skip CPU detection when compilation is disabled. + pie_args+=(--suppress-download-url-method=composer-default --suppress-download-url-method=pre-packaged-source --make-parallel-jobs=1) + fi + if php -r 'exit(PHP_VERSION_ID >= 80100 ? 0 : 1);'; then + if ! command -v pie >/dev/null 2>&1; then + add_tool https://github.com/php/pie/releases/latest/download/pie.phar pie '-V' >/dev/null 2>&1 || return 1 + fi + pie_path=$(command -v pie) || return 1 + else + arch=$(uname -m) + case "$arch" in x86_64|amd64) arch=X64 ;; arm64|aarch64) arch=ARM64 ;; *) return 1 ;; esac + asset="pie-$(uname -s)-$arch" + [ "$(uname -s)" != Darwin ] || asset="pie-macOS-$arch" + pie_path="${tool_path_dir:?}/pie-cli" + if [ ! -x "$pie_path" ]; then + [ "$(get -v -e "$pie_path" "https://github.com/php/pie/releases/latest/download/$asset")" = 200 ] || return 1 + fi + fi + mkdir -p "${composer_home:?}" + set_composer_auth + sudo -E "$pie_path" "${pie_args[@]}" >"/tmp/pie-$extension.log" 2>&1 || { + local status=$? + cat "/tmp/pie-$extension.log" >&2 + return "$status" + } + sudo rm -f /tmp/php"${version:?}"_extensions + enable_extension "$extension" "$prefix" || return 1 + check_extension "$extension" +} + # Function to install PECL extensions and accept default options pecl_install() { local extension=$1