# PHP extensions, php.ini and OPcache on Windows

> Load only the extensions an app needs, keep php.ini per PHP version, tune OPcache safely and verify the loaded configuration.

**Tested on**

- Build: 26100.33650
- Edition: Standard / Datacenter
- Architecture: x64
- Evidence: E1
- Verified: 2026-10-29

## The short answer

Three files matter:

- `php.ini` — the loaded configuration;
- `ext\` — the extension DLLs;
- `php.ini`'s `extension_dir` — where PHP looks for them.

Verify before debugging:

```powershell
php --ini
php -m
php -i | Select-String "Loaded Configuration|extension_dir"
```

If `Loaded Configuration File` is not the file you edited, nothing else matters.

## Extensions

```ini
extension_dir="ext"
extension=curl
extension=mbstring
extension=openssl
extension=pdo_mysql
extension=mysqli
```

Enable only what the app uses. Each extension adds code and patch surface. On Windows the DLL name is usually `php_<name>.dll`; `extension=curl` resolves it under `extension_dir`.

If an extension fails to load, check:

- the DLL exists in `ext`;
- it matches the PHP version/TS-NTS/compiler;
- its dependent DLLs are present;
- the PHP error log says which one failed.

## Per-version and per-site php.ini

With multiple PHP versions, each directory has its own `php.ini`. Do not copy one ini across major versions and expect the extension ABI to match.

For a site-specific ini, set `PHPRC` in the FastCGI environment to that directory. Keep it explicit; otherwise PHP may load `C:\Windows\php.ini` or a previous version’s file.

## OPcache

```ini
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=10000
opcache.validate_timestamps=1
opcache.revalidate_freq=2
```

- `validate_timestamps=1` is safe for development and small sites; PHP checks file mtimes.
- `validate_timestamps=0` is faster but requires a **reload/restart after deploy**; otherwise old code keeps running.
- Do not enable experimental JIT “because faster” without testing the app and measuring.

Verify:

```powershell
php -i | Select-String "opcache.enable|opcache.memory"
```

A phpinfo page shows the same, but remove it after testing.

> **Caution: Do not copy php.ini between major versions**
>
> PHP 8.3 and 8.4 can have different extension ABIs and defaults. Keep a per-version baseline, diff it during upgrades, and change one extension at a time.

## Production baseline

```ini
expose_php=Off
display_errors=Off
log_errors=On
error_log="C:\PHP\logs\php-error.log"
date.timezone=UTC
memory_limit=256M
max_execution_time=60
upload_max_filesize=32M
post_max_size=32M
```

`post_max_size` must be >= `upload_max_filesize`, and IIS/Nginx limits must be >= both.

## Verify

```powershell
php --ini
php -m
php -r "echo ini_get('memory_limit'), PHP_EOL;"
```

Then call a page that uses the extension (`PDO`, `curl`, `mbstring`) instead of trusting `php -m` alone.

## Lab boundary

E1. PHP 8.4.27 FastCGI was verified on VM 361; extension/OPcache settings were not load-tested on Server 2025.

## Sources

- [PHP — Configuration file](https://www.php.net/manual/en/configuration.file.php)
- [PHP — OPcache](https://www.php.net/manual/en/opcache.configuration.php)

---

Source: https://windows.homes/en/server/runtimes/php-config/
