Work In Progress

This book is currently work in progress. Some sections are not yet written. Thank you for your understanding!

DON'T: Using superglobals ($_REQUEST, $_SERVER, $_GET, $_POST etc)

Another very common problem I have seen in Joomla extensions is developers doing something like this:

$something = $_REQUEST['something'];
// or, worse, this
$whatever = $_SERVER['WHATEVER'];

DO NOT DO THAT. THIS IS A SECURITY ISSUE. There are very few cases where an extension needs access to the raw PHP superglobals, namely if you are writing a security extension and you need to check whether there's potentially malicious data in the request before Joomla sanitizes it. If you are one of the five or so people in the Joomla world writing this kind of software you are unlikely to be reading this. If you are about to say that you have a different, legitimate use case: you do NOT; you just don't know how to use Joomla's input class. Sorry.

Joomla already provides an Input class which can return the filtered and sanitised values of a request or environment parameter. Moreover, it allows other parts of your code and plugins to modify or override the input parameters.

The correct way to get something would be something like this:

$something = \Joomla\CMS\Factory::getApplication()->input->request->getCmd('something', 'default');

If the object you are working with has its own input property use that instead of the global input object shown above. Dispatchers and Controllers do have their own input object which can of course be overridden during instantiation.

If the object you are working with has its own property which gives you access to the application use that instead of going through the CMS Factory. This makes your code reusable and testable across applications.

Do NOT get input variables from your Model or View classes. Your Controller should be the only point where you use the input object to retrieve input parameters. You can pass these values to your model by setting its state. Likewise, your view should only ever read the model's state, not the input directly. This makes your code reusable and testable. It also lets you make changes in the naming of your input parameters only making a change in your controller (and possibly your dispatcher) instead of trying to hunt down random uses spread throughout your code. It also makes you think about the data flow in your application which makes it infinitely easier to debug it.

You should not use the entire request superglobal (e.g. $this->input->getCmd('something') or $this->input->request->getCmd('something')) if you know that a specific piece of data can only come as GET or POST data. Instead, be specific, e.g. $this->input->get->getCmd('something') for GET data and $this->input->post->getCmd('something') for POST data. This prevents input shading. If the same input is present in $_GET, $_POST, $_ENV, $_COOKIE and $_SERVER you will only get one value in the request. Which one? It depends on the PHP configuration (request_order and variables_order configuration keys). While on most servers it's GP (Get and Post, i.e. POST data overrides GET data) it could actually be anything with unpredictable consequences for your extension. For example, some servers may stupidly include cookies in request_order, thereby allowing a hacker to set a cookie on a victim's browser to make your extension do something other than the user's reasonable expectation, e.g. delete or modify a different record than what they were trying to delete / edit.

Do not assume that the data you get from the input object is of a specific scalar type. For example, $this->input->getInt('something') may return an integer, null (the default value) or an array of integers. The latter is something that you are unlikely to have come across but that's the way the get() method of Joomla's input object works. Always check the type of the data you receive, always assume that there is a hacker trying to inject invalid data trying to trip your code up, always assume that any kind of filtering or sanitization may fail to work the way you assume it works.

If you want to access the $_SERVER and $_ENV superglobals; don't. Instead go through $this->input->server and $this->input->env. For example, if I want to get the contents of the HTTP header X-Foo-Bar I should do $this->input->server->getString('HTTP_X_FOO_BAR');.

Remember that Joomla can and will apply its text filters when you use getString. If you want to get the raw data use getRaw or getArray — neither method applies any filtering.

Even though you can access the $_FILES superglobal with the input object — DO NOT DO THAT! You should never handle file uploads directly in your code. Always go through Joomla's \Joomla\CMS\Filesystem\File::upload() method. Do remember that, by default, it will try to prevent unsafe files from being uploaded. If you have a VERY good reason to allow “unsafe” files (e.g. you expect that a ZIP file containing PHP files will be used with your extension) and have taken responsible measures to prevent security issues you can of course set its $allowUnsafe parameter to true. If you need your extension to allow uploading of files with extensions or MIME types which are not media you can of course use custom file upload configuration in your own extension. This means that the excuse you may have had for using $_FILES directly is completely invalid so please don't let me see you ever accessing superglobals again.