Skip to content

Releases: Thavarshan/phpvm

v1.11.0

13 Apr 18:46
fda23d1

Choose a tag to compare

What's New

New Commands

  • phpvm exec <version> <command> [args...] — Run a command with a specific PHP version without globally switching. Uses subshell isolation so your current shell is unaffected.
  • phpvm run <version> [script] [args...] — Shortcut for phpvm exec <version> php <script>.
  • phpvm ls-remote [pattern] — List available PHP versions from your system package manager. Supports pattern filtering (e.g., phpvm ls-remote 8.2).
  • phpvm resolve <version|alias> — Resolve a version descriptor or alias to a locally installed version number.
  • phpvm unload — Remove phpvm from the current shell session (deactivates, removes hooks, unsets all functions/variables).
  • phpvm cache clear — Clear the phpvm cache directory.

New Features

  • --no-use flag on source: source phpvm.sh --no-use loads functions without auto-switching or registering the cd hook. Useful for lazy-loading setups.
  • Bash tab completion: Context-aware completions for commands, installed versions, and alias names. Auto-loaded when phpvm is sourced.
  • Auto-set default alias on first install: The first phpvm install now automatically sets the default alias (matches nvm behaviour).
  • PHPVM_BIN export: After every version switch, $PHPVM_BIN points to the active PHP binary directory.
  • XDG_CONFIG_HOME fallback: PHPVM_DIR now respects $XDG_CONFIG_HOME/phpvm when set.

Bug Fixes

  • hash -r after version switch: Bash command hash table is now invalidated after switching, preventing stale binary resolution.
  • phpvm_current uses printf: Consistent with project conventions.

Improved

  • phpvm list output: Active version marked with -> arrow and green colouring. Default alias shown inline.
  • Help text: All commands now documented as implemented with usage examples.

Testing

  • 78 BATS tests (22 new), 0 failures.
  • ShellCheck clean (0 warnings).

Full Changelog: v1.10.0...v1.11.0

Compatibility

  • macOS bash 3.2 fix: Replaced case inside $() with if/else in ls-remote brew handler to avoid parser bug in bash 3.2.

v1.10.0

28 Mar 09:28
4231327

Choose a tag to compare

What's New

.phpvmrc Auto-Read

phpvm now reads .phpvmrc automatically when you run commands without a version argument — just like nvm reads .nvmrc:

  • phpvm use — reads .phpvmrc → falls back to default alias → errors if neither exists
  • phpvm install — reads .phpvmrc to determine which version to install
  • phpvm exec / phpvm run — detect and report the .phpvmrc version

.phpvmrc takes priority over the default alias.

Automatic cd Hook

When phpvm is sourced into your shell, a cd hook is now registered that automatically switches PHP versions when you enter a directory containing a .phpvmrc:

  • Bash: via PROMPT_COMMAND
  • Zsh: via chpwd_functions
  • Gated behind PHPVM_AUTO_USE=true (the default)
  • Skips switching if already on the correct version
  • Silent when no .phpvmrc is found

Internal

  • New phpvm_read_phpvmrc_version() shared helper
  • 5 new BATS tests for .phpvmrc behaviour
  • All 56 tests passing

v1.9.4

15 Mar 00:33
adc6005

Choose a tag to compare

Fixed

  • Fixed README.MD casing in release.yml: The release workflow referenced README.MD but the file is README.md, causing CI failures on case-sensitive Linux filesystems.

Full Changelog: 1.9.3...1.9.4

v1.9.3

15 Mar 00:30
3ec299f

Choose a tag to compare

Fixed

  • Fixed ShellCheck SC2086 in find_phpvmrc: Double-quoted $depth and $max_depth in arithmetic comparison to prevent globbing and word splitting.

Full Changelog: 1.9.2...1.9.3

v1.9.2

15 Mar 00:27
62b7fc8

Choose a tag to compare

Code Quality Improvements

Changed

  • Namespaced global OS variables: Renamed OS_TYPE, OS_ARCH, MACOS_VERSION, MACOS_MAJOR, MACOS_MINOR, IS_WSL, WSL_VERSION, LINUX_DISTRO, and LINUX_VERSION to PHPVM_-prefixed equivalents to prevent namespace pollution when the script is sourced.
  • Made .phpvmrc search depth configurable: find_phpvmrc now uses PHPVM_PHPVMRC_MAX_DEPTH environment variable (default: 25) instead of a hardcoded value.
  • Replaced echo with printf in version validation: is_valid_version_format() and phpvm_normalize_version() now use printf to avoid potential misinterpretation of version strings.
  • Inlined nested functions in suggest_repository_setup: Removed inner function definitions that were re-created on every call.
  • Fixed word-splitting in brew_unlink_all_php: Replaced for-in-subshell pattern with a safe while-read loop.

Removed

  • Removed unused PHPVM_CACHE_UPDATE_ALTERNATIVES variable.

Full Changelog: 1.9.1...1.9.2

v1.9.1

15 Mar 00:17
570911a

Choose a tag to compare

Fixed

  • Fixed phpvm_debug returning non-zero in non-debug mode: Changed from [ test ] && cmd pattern (which returns exit code 1 when DEBUG is off) to if/then/fi, preventing silent failures in set -e contexts or when used as last statement before return $?.
  • Fixed phpvm_with_lock lock leak on interruption: Moved phpvm_unlock before trap restoration so the lock is released while cleanup traps are still active, eliminating the window where an interrupt could leak the lock.
  • Fixed get_php_binary_path stdout side-effect on Linux: Captured linux_find_php_binary output into a variable before echoing, preventing potential double output when the function's stdout mixed with the fallback path.

Changed

  • Eliminated double initialization: Removed redundant phpvm_init_if_needed calls from install_php, use_php_version, phpvm_current, phpvm_which, list_installed_versions, auto_switch_php_version, and uninstall_php. Initialization is now handled centrally by main() (via phpvm_init_or_die) and the sourced-path entry point, avoiding duplicate detect_system() calls (notably the expensive brew --prefix).
  • Moved package_name computation in install_php: The get_php_package_name call was computed but unused by most package manager branches. It is now only computed in the pacman case arm that actually needs it.

Internal

  • Version bump: Updated to v1.9.1.
  • All tests passing: 51 BATS tests pass.

v1.9.0

30 Jan 10:18

Choose a tag to compare

Fixed

  • Fixed error propagation in version resolution: Commands like phpvm use latest and phpvm install latest now correctly propagate failures from phpvm_resolve_version instead of silently swallowing errors.
  • Fixed state consistency in switch_to_system_php: State file (active_version=system) is now only written AFTER the switch operation succeeds, preventing state lies when brew link operations fail.
  • Fixed apt install/uninstall symmetry: Uninstall now removes php${version}-cli, php${version}-common, and php${version}-fpm packages symmetrically with what install creates.
  • Fixed alias directory reliability: Alias directory creation is now required (not best-effort). If $PHPVM_DIR/alias cannot be created, phpvm fails with a clear error message.
  • Fixed symlink robustness: update_current_symlink now uses command -v php to resolve the actual binary path, ensuring the symlink points to what the shell would execute.
  • Fixed path traversal vulnerability in alias resolution: phpvm_resolve_version now validates alias names before file access, preventing path traversal attacks like ../../../etc/passwd.
  • Fixed path traversal vulnerability in alias commands: phpvm_alias now validates alias names BEFORE any file path operations.
  • Fixed trap restoration in sourced shells: phpvm_with_lock now explicitly clears traps with trap - SIGNAL when user had no existing trap, preventing phpvm's cleanup traps from being permanently installed in the user's shell session.
  • Fixed init ordering for help/version commands: Moved command parsing before phpvm_init_or_die so phpvm help and phpvm version work without requiring package manager detection or system initialization.
  • Fixed Linux version listing accuracy: Unified all Linux package managers (apt/dnf/yum/pacman) to use phpvm_linux_installed_versions which scans actual binaries, eliminating inaccurate package name listings like 8.2-cli or 8.2-fpm.
  • Fixed system PHP symlink consistency: System switching now calls update_current_symlink to maintain consistent $PHPVM_DIR/current symlink behavior across all switching modes.
  • Fixed alias security vulnerability: Reordered validation in phpvm_alias to validate version format before using it in file path checks, preventing potential path traversal attacks with malicious alias targets.
  • Fixed yum installation strategy: Implemented proper Remi repository detection and naming conventions (php82-php-cli format), replacing incorrect yum install php8.2 approach that would always fail.
  • Fixed lock PID staleness: Added explicit lock_pid="" reset at top of each phpvm_lock loop iteration to prevent stale PID values in error messages.
  • Fixed unversioned PHP formula detection: Homebrew's unversioned php formula is now correctly identified before any unlinking operations, preventing false version matches from system PHP.
  • Fixed phpvm which for unversioned formulas: Correctly returns path to unversioned PHP installed as php formula.
  • Fixed apt package search: pkg_search_php() now explicitly checks for Candidate: (none) to avoid false positives from apt-cache policy.
  • Fixed echo usage in input validation: Replaced echo "$var" | grep with printf '%s\n' "$var" | grep throughout to prevent interpretation of strings like -n, -e, backslash escapes.
  • Fixed phpvm_which() failure propagation: Now properly propagates failures from phpvm_current using || return $?.
  • Fixed shellcheck SC2221/SC2222 warnings: Simplified phpvm_is_sourced() case pattern to avoid overlapping matches.

Changed

  • Introduced command_exists() helper: Replaced 40+ instances of command -v X > /dev/null 2>&1 with single reusable function for cleaner command availability checks.
  • Introduced ensure_phpvm_dirs() function: Consolidated repeated mkdir -p $PHPVM_DIR/X patterns into centralized directory creation function.
  • Introduced brew_link_php_unversioned() function: Extracted duplicate brew link php --force --overwrite logic with error handling into single reusable function.
  • Introduced is_valid_version_format() function: Consolidated duplicate version regex validation pattern into single validation helper.
  • Added brew_php_major_minor() helper: Reads version directly from $HOMEBREW_PREFIX/opt/php/bin/php instead of PATH-based php -r, eliminating conflicts with system PHP.
  • Reordered version switching flow: Now resolves target formula, then unlinks all PHP, then links resolved formula, preventing "version check breaks after unlink" bugs.
  • Improved Linux binary scanning: Broadened skip patterns to prevent accidentally executing PHP helper binaries (*fpm*, *cgi*, *dbg*, *ize*, *config*).
  • Ubuntu/Debian apt packages: Changed from non-existent php8.2 to actual php8.2-cli format used by ondrej/sury PPA.
  • Fedora/RHEL dnf packages: Implemented correct module stream approach instead of fictional versioned packages.
  • Brew availability check: Changed from fragile brew search | grep to stable brew info <formula> API.
  • Trap preservation in phpvm_with_lock(): Now saves and restores user's existing trap handlers instead of clobbering them.
  • Stale lock detection and auto-cleanup: Lock mechanism now checks if lock holder PID is still running and automatically removes stale locks.

Added

  • Interactive shell guard: Auto-switch from .phpvmrc now only runs in interactive shells using case $- in *i*) pattern.
  • Test mode package manager bypass: Test mode now sets sandbox defaults without requiring actual brew/apt/dnf.

Internal

  • Bash-only support documented: Added explicit notice that script requires bash (uses bashisms).
  • Intentional symlink behavior clarified: Added comment explaining update_current_symlink() links to resolved php binary by design.
  • Dnf module stream workflow: Added inline documentation about RHEL/Fedora module stream management.
  • Version bump: Updated to v1.9.0.
  • All tests passing: 51 BATS tests pass (added 4 security tests for path traversal protection).

Full Changelog: 1.8.0...1.9.0

v1.8.0

15 Jan 20:53
d0e216d

Choose a tag to compare

Added

  • Alias management commands: Added phpvm alias and phpvm unalias for version alias creation, listing, and removal.
  • Alias pattern filtering: phpvm alias <pattern> now filters aliases by name.
  • Alias resolution support: Aliases now resolve in phpvm install, phpvm use, and phpvm which.
  • Alias visibility: phpvm list now shows configured aliases.
  • Alias resolution in .phpvmrc: phpvm auto now resolves aliases defined in .phpvmrc.
  • Latest/stable keywords: latest and stable now resolve to the latest installed PHP version.
  • Quality assurance tooling: Added ShellCheck and shfmt configuration, a QA Makefile, and a qa.sh runner script.
  • BATS test suite: Added comprehensive BATS tests for core functionality and new alias behavior.
  • CI quality workflow: Added a quality workflow for linting, formatting, and tests.

Changed

  • Help output: Promoted alias commands to the primary usage section.

Removed

  • Built-in test command: Removed phpvm test command in favor of BATS test suite only.

Internal

  • Alias helper utilities: Added alias listing helper and alias resolution logic.
  • Test coverage: Extended BATS test suite to cover alias functionality and all core features.

Full Changelog: 1.7.0...1.8.0

v1.6.0

15 Jan 20:50
1.6.0
1aa59f3

Choose a tag to compare

Added

  • Smart repository detection: Added intelligent detection of missing PHP repositories on RHEL/Fedora systems with automatic suggestions for enabling Remi's repository.
  • Enhanced error messaging: Implemented comprehensive error handling with actionable solutions when PHP packages are not found in default repositories.
  • Repository setup guidance: Added detailed step-by-step instructions for enabling EPEL and Remi repositories on Fedora, RHEL, Rocky Linux, AlmaLinux, and CentOS systems.

Changed

  • Consolidated GitHub Actions workflows: Streamlined CI/CD from 7 separate workflow files down to 3 focused workflows, eliminating duplication while maintaining comprehensive test coverage.
  • Enhanced multi-distribution testing: Expanded automated testing to cover 13 Linux distributions (Ubuntu, Debian, Fedora, Rocky Linux, AlmaLinux, Arch Linux, Alpine Linux) with 4 different package managers (apt, dnf, pacman, apk).
  • Improved cross-platform compatibility: Fixed package installation issues for RHEL-family distributions (Rocky/Alma Linux) and Alpine Linux in CI environments.
  • Streamlined workflow organization: Reorganized tests into logical categories: syntax analysis, core functionality, PHP usage, multi-distribution compatibility, performance testing, and end-to-end integration.
  • Intelligent PHP installation: Enhanced PHP installation process to check package availability before attempting installation and provide specific guidance when packages are missing.

Fixed

  • Fixed coreutils package conflicts: Resolved dnf installation conflicts in Rocky Linux and AlmaLinux by adding --allowerasing flag to handle coreutils-single vs coreutils package conflicts.
  • Fixed Alpine Linux container compatibility: Resolved bash availability issues in Alpine Linux containers by dynamically selecting appropriate shell (sh vs bash) for initial container startup.
  • Fixed virtual package installation: Resolved apt installation failure for awk virtual package by explicitly installing gawk package instead.

Removed

  • Removed emoji characters: Cleaned up all emoji usage from codebase for better terminal compatibility and professional appearance.
  • Removed redundant workflow files: Eliminated duplicate testing workflows (use.yml, comprehensive-test.yml, performance-test.yml, integration-test.yml) by consolidating functionality into main test.yml.

Full Changelog: 1.5.0...1.6.0

v1.7.0

11 Dec 16:32

Choose a tag to compare

Added

  • New phpvm current command: Display the currently active PHP version. Returns the version string, "system", or "none" depending on state.
  • New phpvm which [version] command: Show the full path to the PHP binary for a given version. Supports all package managers (brew, apt, dnf, yum, pacman).
  • New phpvm deactivate command: Temporarily disable phpvm management and restore the original PATH. Useful for debugging or temporarily using system defaults.
  • New ls alias for list: Added phpvm ls as an alias for phpvm list for convenience.
  • Specific exit codes: Implemented consistent exit codes across all commands for better scripting support:
    • 0 - Success
    • 1 - General error
    • 2 - Invalid argument or usage error
    • 3 - Version not found (not available)
    • 4 - Version not installed locally
    • 5 - File or permission error
    • 127 - Unknown command
  • Exit code documentation: Added exit codes section to help output.
  • PATH preservation: phpvm use now stores the original PATH on first activation to enable proper deactivation.

Changed

  • Enhanced help output: Updated help text with new commands, examples, and exit code documentation.
  • Improved error handling: Key functions now return specific exit codes instead of generic error codes.

Full Changelog: v1.6.0...1.7.0