# PHP Extensions and ionCube

> Add or remove PHP extensions from the panel — the ionCube Loader for encoded software like WHMCS included — and add any other Remi extension by hand.

Source: https://www.corepanel.net/docs/php/extensions/
Last updated: 2026-09-02
Part of the CorePanel documentation — https://www.corepanel.net/docs

---

Every CorePanel server starts with the extension set a normal PHP site needs. Beyond that,
**fifteen extensions can be added and removed from the panel** — the ones mainstream
hosting software asks for — and anything else in the Remi repository can still be
installed by hand.

The one thing to hold on to before either route: **an extension belongs to a PHP version,
not to an account**. There is one php-fpm master per version and one set of extensions
behind it, so installing `imagick` for PHP 8.3 gives it to every account running 8.3.
That is a property of PHP, not a CorePanel limitation — see
[It applies to a whole PHP version](#it-applies-to-a-whole-php-version).

## From the panel

**PHP → Extensions**, in the admin area. Pick a version along the top; the list underneath
is that version's.

Each extension shows one of:

| State | What it means |
|---|---|
| **installed** | The package is here and the interpreter loads it |
| **installed, not loaded** | The package is here but PHP does not load it — its `.ini` was disabled by hand |
| **not in the repository** | Your package repository does not offer it for that version |
| **not for this version** | It does not exist for that PHP branch at all. Normal, not a fault |

The catalogue is fifteen extensions, not the repository's ~180: `imagick`, `redis`,
`memcached`, `soap`, `ldap`, `imap`, `bcmath`, `posix`, `ioncube-loader`, `sodium`, `gmp`,
`tidy`, `apcu`, `igbinary` and `mongodb`. Anything else somebody installed over SSH is listed
underneath as *installed outside CorePanel* — it works exactly as it did, it is simply not
CorePanel's to add or remove.

The same from a shell:

```bash
corepanel php extensions                          # every version
corepanel php extensions --php 8.3                # just one
corepanel php extensions install 8.3 imagick
corepanel php extensions remove 8.3 imagick
```

> **Both directions restart PHP for that version**
>
> Installing or removing an extension restarts the version's php-fpm master, which
> interrupts requests in flight for **every account on that version**. It lasts a moment.
>
> This is not something CorePanel chooses: the Remi packages carry a trigger that restarts
> php-fpm whenever their configuration directory changes, and it fires on install exactly as
> it does on removal.
### Removals that are refused

Removing an extension another installed package depends on is **refused**, and the message
names what would have gone with it. `dnf remove` takes dependents along: the `redis`
extension requires `igbinary`, so removing igbinary would quietly uninstall redis too — and
the site that stops caching belongs to an account whose owner was never asked.

Remove the dependent extension first if that is genuinely what you want.

The other direction is not blocked, and is worth knowing about: removing an extension also
removes **its own dependencies, if nothing else needs them**. Taking `redis` off a server
removes `igbinary` and `msgpack` with it, because they were only ever there to support it.
An extension you installed yourself is safe — the package manager leaves explicitly
installed packages alone — and the console lists everything that went, either way.

## What is installed

The extensions actually loaded by one PHP version:

```bash
php84 -m            # or php83, php82, php74
```

And the base set every version starts with:

```bash
rpm -q --requires corepanel-php
```

CorePanel does not manage `php.ini` or the `php.d` directory. It writes one file per
account under `/etc/opt/remi/php<version>/php-fpm.d/<username>.conf` and nothing else, so
anything you add to `php.d` is yours and survives updates.

## Encoded software: the ionCube Loader

**Commercially encoded PHP** — WHMCS, licensing systems and many paid scripts ship their
source encrypted with ionCube and refuse to run without the Loader — is in the catalogue as
`ioncube-loader`, so it installs from **PHP → Extensions** like anything else, once per
version:

```bash
corepanel php extensions install 8.4 ioncube-loader
```

There is nothing to download from ionCube's website and nothing to compile: the Loader is
packaged in the **Remi repository**, which CorePanel enables during installation, and it
exists for every PHP version CorePanel installs.

It is the one extension whose name in the panel is not the name PHP prints. `php -m` calls
it *ionCube Loader* and `php -v` calls it *the ionCube PHP Loader*, because it is a
`zend_extension` rather than an ordinary module. The panel handles that; it is worth knowing
if you are reading the output yourself:

```bash
php84 -v
```

The output gains a line naming *the ionCube PHP Loader*. If it does not appear after a
hand-install, the restart is usually what is missing — a `zend_extension` is read when the
PHP process starts, so a running FPM master keeps serving without it. Installing from the
panel restarts it for you.

### What the package puts on disk

Two files per PHP version, and that is the whole installation:

| Path | What it is |
|---|---|
| `/etc/opt/remi/php84/php.d/01-ioncube_loader.ini` | The `zend_extension` line that loads it |
| `/opt/remi/php84/root/usr/lib64/php/modules/ioncube_loader.so` | The Loader itself |

The `01-` prefix matters and is why the packaged version is the one to use: ionCube has to
be loaded **before OPcache**, and the numbering guarantees that ordering. A Loader
downloaded from ionCube and dropped into `php.ini` by hand is the usual cause of "it is
installed but PHP does not see it".

Because the `.ini` lives in the version's shared `php.d`, one install covers **both the
web pools and the command line** — so encoded software also runs from
[cron jobs](https://www.corepanel.net/docs/accounts/cron-jobs) and from SSH, with no extra step.

## After migrating from cPanel

cPanel's `ea-php` builds are its own packages and CorePanel's versions come from Remi, so
the two never share an extension set. Which extensions you end up with depends on how the
server got here.

**[Transformed in place](https://www.corepanel.net/docs/cpanel-transform)** — PREPARE does the comparison for you.
It reads what every cPanel interpreter loads, installs the difference from this catalogue
before any account is registered, and names anything the catalogue does not carry.
VERIFY checks it again afterwards, per version. Nothing on this page needs doing by hand.

**[Imported from another server](https://www.corepanel.net/docs/cpanel-import)** — the accounts arrive, the
extensions do not. Read the source server before you start, per version its accounts use:

```bash
# on the cPanel server
/opt/cpanel/ea-php81/root/usr/bin/php -m
```

and put the difference back from **PHP → Extensions**.

`ioncube-loader`, `imap`, `bcmath`, `posix` and `soap` are the five that come up most
often — a WHMCS install is usually four of them at once. ionCube is the one worth checking
first, because software encoded with it does not fail loudly when the loader is missing: it
answers `200 OK` with a polite page saying it cannot run, which is exactly what an uptime
check reads as a healthy site.

## It applies to a whole PHP version

Every extension on this page — the fifteen in the panel and anything installed by hand — is
enabled **per PHP version, not per account**. Installing one for PHP 8.4 enables it for
every account running PHP 8.4.

This is a property of PHP itself, not a CorePanel limitation. There is one php-fpm master
per version and it loads its extensions when it starts; an FPM pool can override `php.ini`
*settings* per account, but it cannot load or unload a module. Giving one account its own
extension set would mean giving it its own PHP process, and that is not what a shared
server is.

In practice it costs little. An extension no site uses is inert — it adds a small amount of
memory per PHP process and does not change how ordinary PHP runs. The one to think twice
about is **removal**: it takes the extension away from every account on the version at once.

> **Cover every version in use, not just the default**
>
> An account's PHP version is chosen when it is created and can be
> [changed later](https://www.corepanel.net/docs/accounts/editing#changing-the-php-version) — so install what your
> customers need on every version they actually run. Checking only the default version is how
> a migrated account on an older PHP ends up with a white page, and moving an account to a
> version missing an extension its site needs does the same thing the moment you save.
## Keeping it after updates

`dnf update` keeps every extension current along with everything else, and CorePanel never
removes one — an update only touches files the panel owns.

One case does need you: **a PHP version you install later starts with the base set only**.
Extensions are per version, so a server where 8.3 has `imagick` and `redis` gets neither
when you add 8.4 — the panel will show them as *available* on the new version, and one
click each puts them there. The same applies to anything installed by hand, the ionCube
Loader included.

> **An update restarts PHP too**
>
> The same Remi trigger that restarts php-fpm when you add an extension fires on a routine
> `dnf update` of PHP. That is mostly good news — a security fix takes effect without anybody
> intervening — but it is why a PHP update is a moment of interrupted requests as well.
## Adding anything else by hand

For an extension outside the fifteen, the same pattern covers the rest of the Remi
catalogue — the package name is `php<version>-php-<extension>`:

```bash
dnf install php84-php-pecl-yaml
systemctl restart php84-php-fpm
```

Three things worth knowing before you do:

- **Install it for each version you need.** The packages are independent per version;
  `php84-php-soap` does nothing for an account on PHP 8.3.
- **A wrong name only warns.** `dnf install` prints *No match for argument* and exits
  successfully, so a typo looks like a successful install. Confirm with `php84 -m` rather
  than trusting the transaction.
- **The name changes between versions, and not predictably.** Remi builds `imagick`
  against ImageMagick 6 and 7 under different package names from PHP 8.2 onwards, ships
  three `redis` clients for 7.4 and one for 8.4, and moved `imap` out to PECL in 8.4 (so it
  is `php83-php-imap` but `php84-php-pecl-imap`). Check
  with `dnf repoquery 'php84-php-*<name>*'` rather than assuming the name you used last
  time. Sparing you exactly this is why the fifteen in the panel are a declared table of
  (version, package) pairs rather than a guess.
- **It changes between EL majors too.** `imagick` is the one that does today: AlmaLinux
  and Rocky 8 and 9 get the ImageMagick 6 build (`-im6`), because that is the ImageMagick
  the distribution ships and everything else on the host links against. RHEL 10 dropped
  it, so Remi builds only `-im7` there and that is what the panel installs. You do not
  have to think about this from the panel or the CLI — the right one is picked for your
  server — but it matters if you are typing a package name yourself.

Whatever you install by hand shows up in the panel as *installed outside CorePanel*, so
nothing you add disappears from view.

If an extension is not in Remi at all, prefer a `pecl` build over editing `php.ini` by
hand, and always drop the resulting `.ini` in the version's `php.d` directory so ordering
and updates keep working the way they do for everything else.
