Installing PHP directly provides a predictable interpreter for Composer workflows, cron jobs, command-line maintenance, and later web-server integration without hiding the runtime inside a bundled stack.
On Windows, the official downloads page ships prebuilt ZIP archives with separate thread-safe and non-thread-safe builds, so the first install can stay focused on the CLI runtime and its php.ini tree. On Ubuntu or Debian, the distro-default php-cli package provides the shell interpreter through APT, keeping security updates and follow-on extension packages on the normal repository path.
Current Windows manual installation still depends on the matching Microsoft Visual C++ Redistributable for Visual Studio 2015-2022, and the official downloads page currently publishes x64 and x86 builds with x64 recommended for most systems. On Ubuntu 24.04 LTS, php-cli resolves to php8.3-cli, while Debian 13 stable currently resolves it to php8.4-cli, so package names, configuration paths, and php -v output vary by platform and by any pinned repositories.
Related: How to install PHP on Ubuntu or Debian
Related: How to install PHP on CentOS, Fedora, or Red Hat
Related: How to install PHP on SUSE
Related: How to install PHP on macOS
Methods to install PHP on Windows or Linux:
Installing the official ZIP build keeps the first Windows install explicit, which is useful when the runtime will be used from PowerShell, Composer, scheduled tasks, or FastCGI before a web server is introduced. It also makes the PHP directory, php.ini, and Path changes easy to review later.
The Windows downloads page now also exposes package-manager entry points such as Winget and Chocolatey, but the ZIP build remains the clearest manual path when the goal is a standalone interpreter with predictable files under one directory. Choose NTS when PHP will run on the CLI or through FastCGI, and choose TS only when PHP must load directly as a multithreaded web-server module such as Apache mod_php.
Use a writable directory such as $env:LOCALAPPDATA\Programs\PHP instead when administrative access to C:\ is not available, and substitute that path in the remaining commands.
Use the x64 redistributable for x64 builds and the x86 redistributable for x86 builds. Supported current builds require at least Windows 8 or Windows Server 2012.
Choose NTS for CLI or FastCGI use, and choose TS only when PHP will load directly as an Apache module.
PS> $phpZip = Get-ChildItem "$env:USERPROFILE\Downloads\php-*.zip" | >> Sort-Object LastWriteTime -Descending | >> Select-Object -First 1 PS> New-Item -ItemType Directory -Path C:\php -Force Directory: C:\ Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 3/26/2026 9:05 AM php PS> Expand-Archive -Path $phpZip.FullName -DestinationPath C:\php -Force
If more than one PHP ZIP file exists in Downloads, point $phpZip at the exact archive selected from the downloads page before extracting it.
PS> Copy-Item C:\php\php.ini-development C:\php\php.ini
Use php.ini-production instead when the runtime is being prepared for a server-focused baseline.
Related: How to find PHP configuration files
PS> $currentPath = [Environment]::GetEnvironmentVariable('Path', 'User') PS> $pathAlreadySet = $false PS> if (-not [string]::IsNullOrWhiteSpace($currentPath)) { >> $pathAlreadySet = ($currentPath -split ';') -contains 'C:\php' >> } PS> if (-not $pathAlreadySet) { >> $newPath = if ([string]::IsNullOrWhiteSpace($currentPath)) { 'C:\php' } else { "$currentPath;C:\php" } >> [Environment]::SetEnvironmentVariable('Path', $newPath, 'User') >> }
Do not overwrite the existing PATH value. Append the PHP directory to the current value instead.
PS> (Get-Command php).Source C:\php\php.exe PS> php -v PHP 8.5.4 (cli) (built: Mar 10 2026 23:37:22) (NTS Visual C++ 2022 x64) Copyright (c) The PHP Group Zend Engine v4.5.4, Copyright (c) Zend Technologies PS> php --ini | Select-String 'Loaded Configuration File' Loaded Configuration File: C:\php\php.ini
The exact version line follows the ZIP file selected from the current downloads page.
Related: How to check PHP version
Installing PHP from APT keeps Ubuntu and Debian on the packaged runtime path, which is usually the safest starting point for local scripting, automation, containers, and later web-server integration. The distro package manager continues to handle library dependencies, security updates, and matching extension packages after the first install.
The php-cli package is a small dependency package that resolves to the distro's current versioned CLI build, while separate php-* packages add modules such as cURL, MySQL, and XML support. That split keeps the first install focused on the shell runtime instead of pulling in PHP-FPM, mod_php, or php-cgi before the host actually needs a web-facing SAPI.
$ sudo apt-get update
$ apt-cache policy php-cli
php-cli:
Installed: (none)
Candidate: 2:8.3+93ubuntu2
Version table:
2:8.3+93ubuntu2 500
##### snipped #####
$ apt-cache depends php-cli
php-cli
Depends: php8.3-cli
Current package pages map php-cli to php8.3-cli on Ubuntu 24.04 LTS. Current Debian 13 stable maps the same package to php8.4-cli and currently publishes php-cli 2:8.4+96.
$ sudo apt-get install --yes php-cli ##### snipped ##### Setting up php8.3-cli (8.3.6-0ubuntu0.24.04.7) ... Setting up php-cli (2:8.3+93ubuntu2) ... update-alternatives: using /usr/bin/php.default to provide /usr/bin/php (php) in auto mode
The broader php metapackage can pull in a web-facing SAPI such as Apache mod_php, PHP-FPM, or php-cgi. Keep the first install on php-cli when only the shell runtime is needed.
Related: Install PHP-FPM on Ubuntu or Debian
$ php -v
PHP 8.3.6 (cli) (built: Jan 27 2026 03:09:47) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.6, Copyright (c) Zend Technologies
with Zend OPcache v8.3.6, Copyright (c), by Zend Technologies
Current Debian 13 stable reports PHP 8.4.16 (cli) instead because the default php-cli dependency resolves to php8.4-cli there.
Related: How to check PHP version
$ sudo apt-get install --yes php-curl php-mysql php-xml
These unversioned package names resolve to the distro-default branch, such as php8.3-curl on Ubuntu 24.04 LTS or php8.4-curl on Debian 13 stable.
$ php -m | grep -E '^(curl|mysqli|mysqlnd|pdo_mysql|xml|xmlreader|xmlwriter)$' curl mysqli mysqlnd pdo_mysql xml xmlreader xmlwriter
If the host also serves PHP through Apache or PHP-FPM, restart that web-facing runtime after adding modules so it loads the new extension set.
Related: How to show loaded PHP extensions