Joomla PHP & MySQL changes: Joomla 3 → 4, 5 and 6
18 issues in this guide
PHP and MySQL sit under every Joomla upgrade. This guide groups 18 catalog entries on runtime and driver breaks that kill a site before namespaced CMS classes matter. Covered calls and symbols include JArrayHelper, JCryptCipherMcrypt, JString, JStringInflector, DS, $this->foo = 1 on an untyped class, each($array), eval($code), extract($_REQUEST), optional, and 8 more. The shared replacement pattern is: stop calling removed PHP functions, declare properties or use AllowDynamicProperties where you still need dynamic state, talk to the database only through Joomla DatabaseInterface / mysqli / PDO, and import Joomla\String\StringHelper or Joomla\Utilities\ArrayHelper instead of J-prefixed globals. Hop mix in this data: 16 at Joomla 3 → 4; 1 at Joomla 4 → 5; 1 at Joomla 5 → 6. Work each entry below for the exact before/after code, error strings, and symptoms from the catalog. Nothing here invents upgrade statistics beyond those entries. Catalog replacements in this guide include JArrayHelper → Joomla\Utilities\ArrayHelper; JCryptCipherMcrypt → CryptCipherCrypto / Sodium / OpenSSL; JString → Joomla\String\StringHelper; JStringInflector → Joomla\String\Inflector / Normalise. Open each h2 anchor for the full before/after, fix list, and error strings shipped in the reference data.
JARRAYHELPER-CLASS-001
JArrayHelper
JArrayHelper
JArrayHelper left core. Treat it as gone on Joomla 4 even if a leftover map appears — ship ArrayHelper.
JArrayHelper → Joomla\Utilities\ArrayHelper
Dies at Joomla 3 → 4What you will see
- Class "JArrayHelper" not found
Symptoms people search
toInteger fatal · array helper missing
Replace this code
Swap JArrayHelper for Joomla\Utilities\ArrayHelper.
Joomla 3
Remove or stop calling this
JArrayHelper::toInteger($cid);
JArrayHelper::fromObject($obj);Joomla 4 / 6
Use this instead
use Joomla\Utilities\ArrayHelper;
ArrayHelper::toInteger($cid);How to fix it
- 1Replace JArrayHelper with Joomla\Utilities\ArrayHelper.
Also known as
JArrayHelper · ArrayHelper
JCRYPT-MCRYPT-001
JCryptCipherMcrypt
JCryptCipherMcrypt / 3Des / Blowfish / Simple
Weak and mcrypt-based ciphers were removed. PHP mcrypt is gone too.
JCryptCipherMcrypt → CryptCipherCrypto / Sodium / OpenSSL
Dies at Joomla 3 → 4What you will see
- Class "JCryptCipherMcrypt" not found
- Class "JCryptCipher3Des" not found
- Call to undefined function mcrypt_encrypt
Symptoms people search
cannot decrypt config · mcrypt
Replace this code
Swap JCryptCipherMcrypt for CryptCipherCrypto / Sodium / OpenSSL.
Joomla 3
Remove or stop calling this
$crypt = new JCrypt(new JCryptCipherMcrypt());Joomla 4 / 6
Use this instead
Use Joomla\CMS\Crypt\Cipher\CryptoCipher. Do not use mcrypt.How to fix it
- 1Re-encrypt data with Sodium/OpenSSL ciphers.
- 2You cannot decrypt old mcrypt blobs without a one-off migrator.
Also known as
mcrypt · JCryptCipher3Des · JCryptCipherBlowfish · JCryptCipherSimple · hasStrongPasswordSupport
There is no 1:1 swap for this one. The architecture changed. If you cannot rewrite it, Infyways can.
JSTRING-CLASS-001
JString
JString / StringHelper
JString was removed in Joomla 4. There is no reliable class alias. UTF-8 string helpers live in the joomla/string package.
JString → Joomla\String\StringHelper
Dies at Joomla 3 → 4What you will see
- Class "JString" not found
- Call to undefined method JString::
Symptoms people search
utf8 strlen broken · JString after Joomla 4
Replace this code
Swap JString for Joomla\String\StringHelper.
Joomla 3
Remove or stop calling this
echo JString::strtoupper($name);
$len = JString::strlen($utf8);Joomla 4 / 6
Use this instead
use Joomla\String\StringHelper;
echo StringHelper::strtoupper($name);How to fix it
- 1Replace JString with StringHelper.
- 2Add use Joomla\String\StringHelper.
Also known as
JString · StringHelper · phputf8
JSTRINGINFLECTOR-001
JStringInflector
JStringInflector / JStringNormalise
These JString satellites were obsolete in Joomla 4. Use the String package classes.
JStringInflector → Joomla\String\Inflector / Normalise
Dies at Joomla 3 → 4What you will see
- Class "JStringInflector" not found
- Class "JStringNormalise" not found
Symptoms people search
pluralize helper fatal
Replace this code
Swap JStringInflector for Joomla\String\Inflector / Normalise.
Joomla 3
Remove or stop calling this
JStringInflector::getInstance()->toPlural('item');
JStringNormalise::toDashSeparated($s);Joomla 4 / 6
Use this instead
use Joomla\String\Inflector;
use Joomla\String\Normalise;How to fix it
- 1Switch Inflector and Normalise to the Joomla\String namespace.
Also known as
JStringInflector · JStringNormalise
PHP-DS-001
DS
DS path constant
DS was a Joomla shortcut for the directory separator. It was removed in Joomla 4. PHP already has DIRECTORY_SEPARATOR. Forward slashes work on Windows in PHP.
DS → DIRECTORY_SEPARATOR or /
Dies at Joomla 3 → 4What you will see
- Undefined constant DS
- Use of undefined constant DS
Symptoms people search
helper path broken · failed to open stream after upgrade
Replace this code
Swap DS for DIRECTORY_SEPARATOR or /.
Joomla 3
Remove or stop calling this
$path = JPATH_COMPONENT . DS . 'helpers' . DS . 'foo.php';Joomla 4 / 6
Use this instead
$path = JPATH_COMPONENT . '/helpers/foo.php';How to fix it
- 1Replace DS with '/' inside Joomla paths.
- 2Or use DIRECTORY_SEPARATOR if you concatenate OS paths.
Also known as
DS · directory separator
PHP-DYNAMIC-PROP-001
$this->foo = 1 on an untyped class
Dynamic PHP properties (PHP 8.2+)
Joomla 5/6 run on PHP 8.2–8.4. Creating undeclared properties is deprecated and will be removed. Joomla 3 code did this constantly.
$this->foo = 1 on an untyped class → Declare the property or use AllowDynamicProperties
Dies at Joomla 4 → 5What you will see
- Creation of dynamic property
- Deprecated: Creation of dynamic property
Symptoms people search
php 8.2 deprecation flood · dynamic property
Replace this code
Swap $this->foo = 1 on an untyped class for Declare the property or use AllowDynamicProperties.
Joomla 3
Remove or stop calling this
class LmsHelper {
public function set($k, $v) { $this->$k = $v; }
}Joomla 4 / 6
Use this instead
class LmsHelper {
public string $name;
}
// or #[\AllowDynamicProperties] as a last resortHow to fix it
- 1Declare properties on the class.
- 2Avoid #[AllowDynamicProperties] except as a temporary bridge.
Also known as
dynamic property · AllowDynamicProperties
PHP-EACH-001
each($array)
each() / create_function() / ereg / split
These PHP functions were removed long before Joomla 6. Joomla 4 already needs PHP 7.2+; Joomla 5 needs 8.1; Joomla 6 needs 8.3. Old extension code still contains them.
each($array) → foreach / closures / preg_*
Dies at Joomla 3 → 4What you will see
- Call to undefined function each()
- Call to undefined function create_function()
- Call to undefined function ereg()
- Call to undefined function split()
- Call to undefined function get_magic_quotes_gpc()
Symptoms people search
php 8 fatal in a helper file
Replace this code
Swap each($array) for foreach / closures / preg_*.
Joomla 3
Remove or stop calling this
while (list($k, $v) = each($rows)) { }
$fn = create_function('$a', 'return $a;');Joomla 4 / 6
Use this instead
foreach ($rows as $k => $v) { }
$fn = static fn ($a) => $a;How to fix it
- 1each() → foreach.
- 2create_function() → a closure.
- 3ereg/split → preg_match / explode / preg_split.
- 4get_magic_quotes_gpc() → delete; filter input instead.
Also known as
each · create_function · ereg · split · magic_quotes
PHP-EVAL-001
eval($code)
eval() in extensions
eval still runs. It is an RCE footgun. Joomla 6 migrations should remove it, not preserve it.
eval($code) → Never — forbidden for Infyways work
Dies at Joomla 3 → 4Symptoms people search
eval in plugin · custom php param
Replace this code
Swap eval($code) for Never — forbidden for Infyways work.
Joomla 3
Remove or stop calling this
eval($params->get('customphp'));Joomla 4 / 6
Use this instead
// Delete eval. If you need configurable logic, use a real PHP class, not stored strings.How to fix it
- 1Remove eval.
- 2Rewrite as proper code.
Also known as
eval(
There is no 1:1 swap for this one. The architecture changed. If you cannot rewrite it, Infyways can.
PHP-EXTRACT-001
extract($_REQUEST)
extract($_GET) / extract($_POST)
extract on superglobals overwrites local variables. It still runs on Joomla 6 and is still wrong.
extract($_REQUEST) → Input API, named variables
Dies at Joomla 3 → 4Symptoms people search
extract post · variable overwrite
Replace this code
Swap extract($_REQUEST) for Input API, named variables.
Joomla 3
Remove or stop calling this
extract($_POST);
echo $title;Joomla 4 / 6
Use this instead
$title = $app->getInput()->getString('title');How to fix it
- 1Delete extract($_GET/$_POST/$_REQUEST).
- 2Read keys through Input.
Also known as
extract($_POST) · extract($_GET) · extract($_REQUEST)
There is no 1:1 swap for this one. The architecture changed. If you cannot rewrite it, Infyways can.
PHP-GMP-001
optional
PHP gmp extension (WebAuthn)
Joomla 4+ WebAuthn/passkeys need GMP. Upgrades fail or MFA breaks without it.
optional → Enable ext-gmp on PHP 8.1+
Dies at Joomla 3 → 4What you will see
- Class "GMP" not found
- gmp_init()
Symptoms people search
passkey error · webauthn · gmp
Replace this code
Swap optional for Enable ext-gmp on PHP 8.1+.
Joomla 3
Remove or stop calling this
// Joomla 3 sites often omitted gmpJoomla 4 / 6
Use this instead
php.ini: extension=gmp (required for passkeys / WebAuthn on many J4+ hosts)How to fix it
- 1Enable gmp (and sodium/openssl).
- 2Confirm with phpinfo on staging.
Also known as
gmp · WebAuthn · passkeys
PHP-JEXEC-001
defined('_JEXEC') or die;
defined('_JEXEC') or die;
This is not deprecated. Direct-hit PHP files without it are a security hole on every Joomla version. Do not delete it while “cleaning J3”.
defined('_JEXEC') or die; → Keep it on every entry PHP file
Dies at Joomla 3 → 4Symptoms people search
restricted access · _JEXEC
Replace this code
Swap defined('_JEXEC') or die; for Keep it on every entry PHP file.
Joomla 3
Remove or stop calling this
defined('_JEXEC') or die('Restricted access');Joomla 4 / 6
Use this instead
defined('_JEXEC') or die;How to fix it
- 1Keep _JEXEC on every web-reachable PHP file except the real entry points.
Also known as
_JEXEC · defined('_JEXEC') · Restricted access
PHP-JPATH-PLATFORM-001
JPATH_PLATFORM
JPATH_PLATFORM
JPATH_PLATFORM pointed at the old libraries tree. That layout is gone.
JPATH_PLATFORM → Do not use — autoload instead
Dies at Joomla 3 → 4What you will see
- Undefined constant JPATH_PLATFORM
Symptoms people search
library path fatal
Replace this code
Swap JPATH_PLATFORM for Do not use — autoload instead.
Joomla 3
Remove or stop calling this
require JPATH_PLATFORM . '/joomla/foo.php';Joomla 4 / 6
Use this instead
use the namespaced class. Do not require files out of libraries/src.How to fix it
- 1Remove requires that use JPATH_PLATFORM.
- 2Use a use statement for the CMS class.
Also known as
JPATH_PLATFORM
PHP-MYSQL-001
mysql_query()
mysql_* PHP functions
mysql_* was removed from PHP 7. Joomla 4 will not run on PHP that still has it. Direct mysql_query also bypasses Joomla's prefix and ACL.
mysql_query() → Joomla DatabaseInterface / mysqli / PDO
Dies at Joomla 3 → 4What you will see
- Call to undefined function mysql_query()
- Call to undefined function mysql_connect()
Symptoms people search
undefined function mysql_query
Replace this code
Swap mysql_query() for Joomla DatabaseInterface / mysqli / PDO.
Joomla 3
Remove or stop calling this
$res = mysql_query('SELECT * FROM jos_users');Joomla 4 / 6
Use this instead
$db = $this->getDatabase();
$query = $db->getQuery(true)->select('*')->from($db->quoteName('#__users'));
$db->setQuery($query);
$rows = $db->loadObjectList();How to fix it
- 1Replace mysql_* with the Joomla database API and bound parameters.
Also known as
mysql_query · mysql_connect · mysql_fetch
There is no 1:1 swap for this one. The architecture changed. If you cannot rewrite it, Infyways can.
PHP-TYPEHINT-OVERRIDE-001
public function display($tpl = null)
Child class missing Joomla 4 typehints
Joomla 4 added scalar/return types on MVC parents. A J3 subclass that omits them fatals: Declaration must be compatible.
public function display($tpl = null) → Match parent signatures (including types and return)
Dies at Joomla 3 → 4What you will see
- Declaration of ... must be compatible with
- Fatal error: Declaration
Symptoms people search
incompatible declaration · typehint override · PHP fatal on view display
Replace this code
Swap public function display($tpl = null) for Match parent signatures (including types and return).
Joomla 3
Remove or stop calling this
public function display($tpl = null) { parent::display($tpl); }Joomla 4 / 6
Use this instead
public function display($tpl = null): void { parent::display($tpl); }How to fix it
- 1Copy the parent method signature from HtmlView / BaseController / ListModel.
- 2Do not guess — open the Joomla 6 class.
Also known as
must be compatible · Return type · typed properties
PHP-UTF8-LIB-001
jimport('phputf8.utils.unicode')
libraries/phputf8 copy
Joomla 4 removed the bundled phputf8 tree. String work goes through the String package.
jimport('phputf8.utils.unicode') → Joomla\String\StringHelper
Dies at Joomla 3 → 4What you will see
- Failed opening required .../phputf8
- Call to undefined function utf8_strtolower
Symptoms people search
phputf8 missing · utf8_strtolower
Replace this code
Swap jimport('phputf8.utils.unicode') for Joomla\String\StringHelper.
Joomla 3
Remove or stop calling this
jimport('phputf8.utils.ascii');
utf8_strtolower($s);Joomla 4 / 6
Use this instead
use Joomla\String\StringHelper;
StringHelper::strtolower($s);How to fix it
- 1Replace utf8_* helpers with StringHelper.
- 2Do not jimport phputf8.
Also known as
phputf8 · utf8_strtolower · utf8_strlen
PHP-VERSION-FLOOR-001
PHP 5.3–7.x on Joomla 3
PHP version floors (J4 / J5 / J6)
People blame Joomla for fatals that are PHP. each()/mysql_* die on the PHP J4 already required.
PHP 5.3–7.x on Joomla 3 → J4 ≥ 7.2.5 · J5 ≥ 8.1 · J6 ≥ 8.3 (8.4 recommended)
Dies at Joomla 5 → 6What you will see
- Your host needs to use PHP 8.3
- JOOMLA_MINIMUM_PHP
Symptoms people search
joomla 6 php requirement · php 8.3
Replace this code
Swap PHP 5.3–7.x on Joomla 3 for J4 ≥ 7.2.5 · J5 ≥ 8.1 · J6 ≥ 8.3 (8.4 recommended).
Joomla 3
Remove or stop calling this
// Hosting on PHP 7.4 with Joomla 3Joomla 4 / 6
Use this instead
Joomla 6 will not install below PHP 8.3.0. Upgrade PHP before the CMS.How to fix it
- 1Check phpversion() on staging.
- 2Move to 8.3+ before a Joomla 6 update.
Also known as
PHP 8.3 · PHP 8.1 · minimum php
SEC-ECHO-GET-001
echo $_GET['name']
echo $_GET / unescaped output
XSS is not a Joomla-version feature. Joomla 6 still executes it. Migrations should close it.
echo $_GET['name'] → Input + htmlspecialchars / Text
Dies at Joomla 3 → 4Symptoms people search
xss · echo GET
Replace this code
Swap echo $_GET['name'] for Input + htmlspecialchars / Text.
Joomla 3
Remove or stop calling this
echo $_GET['q'];Joomla 4 / 6
Use this instead
echo htmlspecialchars($app->getInput()->getString('q'), ENT_QUOTES, 'UTF-8');How to fix it
- 1Never echo superglobals.
- 2Escape at the edge.
Also known as
$_GET · $_POST · XSS
There is no 1:1 swap for this one. The architecture changed. If you cannot rewrite it, Infyways can.
SEC-UNSERIALIZE-001
unserialize($_POST['data'])
unserialize($_POST) / untrusted input
unserialize on user input is RCE. It “works” on Joomla 6 and is still wrong.
unserialize($_POST['data']) → JSON + validation
Dies at Joomla 3 → 4Symptoms people search
unserialize post · object injection
Replace this code
Swap unserialize($_POST['data']) for JSON + validation.
Joomla 3
Remove or stop calling this
$data = unserialize($_POST['payload']);Joomla 4 / 6
Use this instead
$data = json_decode($app->getInput()->get('payload', '{}', 'RAW'), true);How to fix it
- 1Use JSON.
- 2Never unserialize request data.
Also known as
unserialize
There is no 1:1 swap for this one. The architecture changed. If you cannot rewrite it, Infyways can.