PHP Install
To run PHP code, your computer (or a server) needs the PHP interpreter — the program that reads .php files and executes them. This lesson explains the different ways to install it, how to verify the installation, and how to configure PHP for development.
What Exactly Are You Installing?
A PHP installation contains several parts. Knowing them makes troubleshooting much easier.
| Component | What It Is | Why It Matters |
|---|---|---|
| PHP CLI | The php command you run in a terminal | Runs scripts, the built-in server, and tools like Composer |
| PHP-FPM | A background service that runs PHP for web servers such as Nginx | Used on real servers and full local stacks |
| php.ini | The main configuration file | Controls error display, memory limits, upload sizes, extensions, timezone |
| Extensions | Optional modules (for example mbstring, pdo_mysql, curl) | Add features such as database access, multibyte strings, and HTTP requests |
Note: The CLI and PHP-FPM can use different
php.inifiles. A setting you change for the terminal may not apply to your web server. This is one of the most common sources of confusion and is covered under Common Mistakes below.
Choosing an Installation Method
| Method | Best For | Advantages | Limitations |
|---|---|---|---|
| Native install (Windows ZIP, Homebrew, apt) | Learning and everyday development | Fast, uses the real php command, easy to update | You manage extensions and configuration yourself |
| All-in-one stack (XAMPP, Laragon, MAMP) | Quick start with Apache + MySQL included | One installer gives PHP, a web server, and a database | PHP version may lag behind the latest release; hides how parts connect |
| Docker | Teams and matching production exactly | Same environment on every machine, easy version switching | Requires learning Docker basics |
For this tutorial, a native install is recommended. It keeps things simple and teaches you how PHP is actually configured. You can add MySQL separately when you reach the database lessons.
Installing PHP on Windows
Step 1 — Download PHP
- Go to
https://windows.php.net/download/. - Under the latest PHP 8 version, download the x64 Non Thread Safe ZIP file.
Why "Non Thread Safe"? Thread-safe builds are only needed when PHP runs inside a multi-threaded web server module, such as Apache's mod_php on Windows. For the command line, the built-in server, and FastCGI setups, the Non Thread Safe build is the recommended choice because it avoids unnecessary locking overhead.
Step 2 — Extract the Files
Extract the ZIP to a short path without spaces, for example:
C:\php
You should now have C:\php\php.exe.
Step 3 — Add PHP to the PATH
The PATH environment variable tells Windows where to look for programs. Adding C:\php lets you type php in any terminal instead of the full path C:\php\php.exe.
- Press Start, search for "Edit the system environment variables", and open it.
- Click Environment Variables…
- Under User variables, select Path and click Edit.
- Click New and enter
C:\php. - Click OK on every window.
- Close and reopen your terminal. Already-open terminals keep the old
PATH.
Step 4 — Create php.ini
The ZIP contains two template files:
php.ini-development— shows errors, suited to learning and developmentphp.ini-production— hides errors, suited to live servers
Copy php.ini-development and rename the copy to php.ini in the same folder.
Step 5 — Enable Common Extensions
Open C:\php\php.ini in a text editor and find this line:
;extension_dir = "ext"
Remove the leading semicolon:
extension_dir = "ext"
Then remove the semicolon in front of these extension lines:
extension=curl
extension=fileinfo
extension=intl
extension=mbstring
extension=openssl
extension=pdo_mysql
extension=sodium
extension=zip
Why the semicolons? In php.ini, a line starting with ; is a comment. The template ships with most extensions commented out so that you enable only what you need. extension_dir tells PHP the folder where the extension .dll files are stored.
Step 6 — Verify
php -v
Expected output (version numbers will vary):
PHP 8.5.x (cli) (built: ...) (NTS Visual C++ 2022 x64)
Copyright (c) The PHP Group
Zend Engine v4.5.x, Copyright (c) Zend Technologies
If you see 'php' is not recognized as an internal or external command, the PATH step did not take effect — see Common Mistakes.
Alternative: Laragon or XAMPP
If you prefer a graphical installer that also includes Apache and MySQL, Laragon and XAMPP are popular choices on Windows. Check which PHP version they bundle before installing, and note that their php.ini lives inside their own installation folder.
Installing PHP on macOS
macOS no longer ships with PHP. The standard way to install it is with Homebrew, a package manager for macOS.
Step 1 — Install Homebrew (if needed)
Follow the one-line installation command on https://brew.sh.
Step 2 — Install PHP
brew install php
This installs the latest stable PHP version along with common extensions.
To install a specific version instead:
brew install php@8.4
Versioned formulas are not linked automatically. Homebrew prints instructions after installation, usually:
brew link php@8.4 --force --overwrite
Step 3 — Verify
php -v
Step 4 — Find php.ini
php --ini
Example output:
Configuration File (php.ini) Path: /opt/homebrew/etc/php/8.5
Loaded Configuration File: /opt/homebrew/etc/php/8.5/php.ini
Scan for additional .ini files in: /opt/homebrew/etc/php/8.5/conf.d
The paths shown are for Apple Silicon Macs. On Intel Macs, Homebrew uses /usr/local instead of /opt/homebrew.
Installing PHP on Linux (Ubuntu / Debian)
Step 1 — Install PHP and Common Extensions
sudo apt update
sudo apt install php-cli php-mbstring php-xml php-curl php-mysql php-intl php-zip php-gd
What each package provides:
| Package | Purpose |
|---|---|
php-cli | The php command-line interpreter |
php-mbstring | Multibyte (Unicode) string functions such as mb_strlen() |
php-xml | DOM, SimpleXML, XMLReader, and XMLWriter |
php-curl | HTTP requests to other servers and APIs |
php-mysql | MySQLi and PDO MySQL drivers |
php-intl | Internationalization: locale-aware formatting, transliteration |
php-zip | Reading and creating ZIP archives |
php-gd | Image creation and manipulation |
Note: Installing the plain
phppackage on Ubuntu may also install Apache. Installingphp-cliand individual extensions avoids pulling in a web server you may not want.
Ubuntu's official repositories contain one PHP version per Ubuntu release (for example, Ubuntu 24.04 provides PHP 8.3). For newer versions, many developers use the widely used PPA maintained by Ondřej Surý:
sudo add-apt-repository ppa:ondrej/php
sudo apt update
sudo apt install php8.4-cli php8.4-mbstring php8.4-xml php8.4-curl php8.4-mysql
With this PPA, package names include the version number, so several versions can be installed side by side.
Step 2 — Verify
php -v
Configuration File Locations
On Ubuntu, each PHP version and each mode has its own configuration directory:
/etc/php/8.3/cli/php.ini ← used by the php command
/etc/php/8.3/fpm/php.ini ← used by PHP-FPM (web server)
/etc/php/8.3/apache2/php.ini ← used by Apache mod_php
Switching Between Installed Versions
sudo update-alternatives --config php
This shows a numbered list of installed PHP versions and lets you choose which one the php command runs.
Using PHP With Docker
Docker runs PHP inside an isolated container, so you do not install PHP on your system at all. The official php images are published on Docker Hub.
Run a Script
docker run --rm -v "$PWD":/app -w /app php:8.4-cli php hello.php
What Each Part Does
| Part | Meaning |
|---|---|
docker run | Start a new container |
--rm | Delete the container when it finishes, so stopped containers do not pile up |
-v "$PWD":/app | Mount the current folder into the container at /app, so PHP can see your files |
-w /app | Set the working directory inside the container |
php:8.4-cli | The official image: PHP 8.4, command-line variant |
php hello.php | The command to run inside the container |
Run the Development Server
docker run --rm -p 8000:8000 -v "$PWD":/app -w /app php:8.4-cli php -S 0.0.0.0:8000
-p 8000:8000connects port 8000 on your computer to port 8000 in the container.0.0.0.0makes the server listen on all network interfaces inside the container. Usinglocalhosthere would make it unreachable from your browser, becauselocalhostinside a container refers to the container itself.
Changing the version is as simple as replacing 8.4 with another tag, which makes Docker useful for testing code against several PHP versions.
Note: On Windows Command Prompt, replace
"$PWD"with"%cd%". In PowerShell, use${PWD}.
Verifying Your Installation
These commands work on every platform.
| Command | What It Shows |
|---|---|
php -v | The installed PHP version |
php -m | All loaded extensions |
php --ini | Which php.ini file is loaded and where extra .ini files are scanned |
php -i | The complete configuration (long output) |
php -r "echo PHP_VERSION;" | Runs a single line of PHP code directly |
Check for a Specific Extension
# Linux / macOS
php -m | grep mbstring
# Windows (Command Prompt or PowerShell)
php -m | findstr mbstring
If the extension name is printed, it is loaded. No output means it is missing or disabled.
Test With a Script
Create check.php:
<?php
echo "PHP version: " . PHP_VERSION . PHP_EOL;
echo "Operating system: " . PHP_OS_FAMILY . PHP_EOL;
echo "Loaded php.ini: " . (php_ini_loaded_file() ?: "none") . PHP_EOL;
echo "mbstring loaded: " . (extension_loaded('mbstring') ? "yes" : "no") . PHP_EOL;
Run it:
php check.php
Output (example)
PHP version: 8.5.1
Operating system: Linux
Loaded php.ini: /etc/php/8.5/cli/php.ini
mbstring loaded: yes
How the Script Works
PHP_VERSION,PHP_OS_FAMILY, andPHP_EOLare predefined constants.PHP_OS_FAMILYreturnsWindows,Darwin(macOS),Linux,BSD,Solaris, orUnknown.PHP_EOLis the correct line ending for the current operating system.- The
.operator joins strings together (string concatenation). php_ini_loaded_file()returns the path of the loadedphp.ini, orfalseif none was loaded.?:is the short ternary operator: if the left side is falsy (such asfalse), the right side"none"is used instead.extension_loaded('mbstring')returnstrueorfalse, and the ternary? "yes" : "no"turns that into readable text.
A missing php.ini ("none") is a common reason why extensions are not loaded, so this script quickly reveals configuration problems.
Configuring php.ini for Development
During development, you want PHP to report every problem loudly. Open the php.ini file shown by php --ini and make sure these values are set:
error_reporting = E_ALL
display_errors = On
display_startup_errors = On
log_errors = On
date.timezone = Asia/Kolkata
What Each Setting Does
| Setting | Effect | Why |
|---|---|---|
error_reporting = E_ALL | Report every type of error, warning, notice, and deprecation | Small warnings often reveal real bugs, such as undefined variables |
display_errors = On | Show errors in the output | You see problems immediately instead of a blank page |
display_startup_errors = On | Show errors that happen while PHP itself starts | Reveals broken extension configuration |
log_errors = On | Also write errors to the error log | Useful for problems that occur in background requests |
date.timezone | Default timezone for date functions | Ensures date() shows your local time; use your own zone, such as America/New_York or Europe/London |
php.ini-development already contains most of these values. The timezone usually needs to be set manually; when it is not set, PHP uses UTC.
After saving:
- The CLI reads
php.inievery time it starts, so the nextphpcommand uses the new settings. - PHP-FPM and Apache read it only at startup, so you must restart them (for example,
sudo systemctl restart php8.3-fpm).
Warning: Never use
display_errors = Onon a live production server. Error messages can reveal file paths, database names, and query details to attackers. Production configuration is covered in Error Reporting in Production.
Viewing Configuration With phpinfo()
phpinfo() prints a complete HTML report of the PHP configuration.
<?php
phpinfo();
Save it as info.php, start the development server, and open http://localhost:8000/info.php. The page lists the PHP version, loaded php.ini, enabled extensions, and every configuration value.
This is useful because the web server's configuration may differ from the CLI's. phpinfo() shows the configuration as the web server sees it.
Warning: Delete
info.phpafter use. On a public server, this page gives attackers a detailed map of your environment.
Choosing a Code Editor
Any text editor works, but a good editor catches mistakes as you type.
- Visual Studio Code (free) — install a PHP extension such as PHP Intelephense for autocompletion, error detection, and go-to-definition.
- PhpStorm (paid, free for students and some open-source projects) — a full IDE with deep PHP support, refactoring, and debugging tools.
Configure the editor to save files as UTF-8 without BOM. A byte-order mark (BOM) at the start of a file is invisible but is sent as output before your PHP code runs, which can cause the "headers already sent" error discussed in the PHP Tags lesson.
Common Mistakes
'php' is not recognized / php: command not found
Why it happens: The folder containing the PHP executable is not in PATH, or the terminal was opened before PATH was updated.
Fix: Recheck the PATH entry, then close all terminal windows and open a new one. In VS Code, restart the editor, because its integrated terminal inherits the environment from when VS Code started.
Editing the Wrong php.ini
What happens: You change a setting, but nothing changes.
Why it happens: There may be several php.ini files — one for the CLI, one for PHP-FPM, one for Apache, or one per installed version.
Fix: For the CLI, run php --ini. For the web server, check the "Loaded Configuration File" line in phpinfo(). Edit the file that is actually loaded.
"Loaded Configuration File: (none)"
Why it happens: On Windows, the template was not copied to php.ini, or it was saved as php.ini.txt.
Fix: Copy php.ini-development to php.ini in the PHP folder and enable file name extensions in File Explorer to confirm the name.
"Call to undefined function mb_strlen()" (or another extension function)
Why it happens: The extension providing the function is not installed or not enabled.
Fix: Check php -m. On Windows, uncomment the extension= line and confirm extension_dir is set. On Linux, install the package (for example php-mbstring). Restart PHP-FPM or Apache if the error appears in the browser.
Changes Not Applied to the Website
Why it happens: PHP-FPM and Apache keep the configuration they loaded at startup.
Fix: Restart the service after editing its php.ini.
Different Versions in the Terminal and the Browser
What happens: php -v shows 8.4, but phpinfo() shows 8.3.
Why it happens: The CLI and the web server are using different PHP installations.
Fix: Decide which version you want and configure both to use it — for example, by pointing Nginx to the matching PHP-FPM socket or selecting the version in your local stack's settings.
Best Practices
- Develop on the same major and minor version as production. Code using PHP 8.4 features fails on a PHP 8.2 server. Check your hosting provider's version before choosing language features.
- Install only the extensions you need. Fewer extensions mean less memory use and a smaller attack surface.
- Keep PHP updated within its branch. Patch releases (8.4.1 → 8.4.2) contain bug and security fixes and are designed not to break compatibility.
- Use development settings locally and production settings on servers. Start from the matching template file rather than mixing them.
- Record your PHP requirements in the project. When you start using Composer, declare the required version (for example
"php": ">=8.2") incomposer.jsonso others know which version the project needs.
Official reference: https://www.php.net/manual/en/install.php