6

This is one that has bugged me for several years now - Joomla provided JRequest, and then JInput to access filtered data from the incoming request. You can ask for filtered strings, integers, words etc. Or you can ask for an array (either by just using getVar with the variable name alone and assuming/checking that the value returned is an array, or by forcing the matter by supplying a few extra parameters to it).

But you can't ask for an array of integers, words etc.

Am I missing something?

For example, my POST data might include:

stuff[abc]=1
stuff[def]=75
stuff[123]=<script src="http://imanaughtysite.com/muahahaha.js"/>

How do I ask JInput for 'stuff' as an array of integers?

  • Please define a clear problem or give some examples of input arrays that you would like to filter. As it stands the question in not specific enough. Getting answers like 'it is not possible ' shows that the problem is vague. – Valentin Despa Nov 13 '14 at 21:30
  • Example added. That said, the answers provided clearly reflected understanding of what I asked and were to the point. I'm actually not clear on how my question could be interpreted as that broad to be honest with you! – John Rix Nov 21 '14 at 1:00
7

OK, so let us look at what options are available. The examples below are using JInput and have been tested in Joomla 3.3.

I am POSTing the following data at Joomla:

stuff[abc]=1
stuff[def]=75
stuff[123]=<script src="http://imanaughtysite.com/muahahaha.js"/>

I want to get a clean array of integers, so the expected result is:

$expectedResult = array(
    'abc' => 1,
    'def' => 75,
    '123' => 0,
);

Option 1 - JInput::get() with ARRAY filter

$a1 = $app->input->get('stuff', array(), 'ARRAY');

Result:

array (size=3)
  'abc' => string '1' (length=1)
  'def' => string '75' (length=2)
  123 => string '<script src="http://imanaughtysite.com/muahahaha.js"/>' (length=54)

BAD IDEA - as you can see, we are getting our data, but it not filtered / cleaned at all!

Option 2 - JInput::getArray() on post

$a2 = $app->input->post->getArray();

Result:

array (size=1)
  'stuff' => 
    array (size=3)
      'abc' => string '1' (length=1)
      'def' => string '75' (length=2)
      123 => string '' (length=0)

Now we have the whole POST array, cleaned. But it is more information that we wanted and it is still not an array of integers.

Option 3 - JInput::getArray() specifying expected parameters and their respective filter:

$a3 = $app->input->getArray(array(
    'stuff' => array(
        'abc' => 'INT',
        'def' => 'INT',
        '123' => 'INT'
    )
));

Result:

array (size=1)
  'stuff' => 
    array (size=3)
      'abc' => int 1
      'def' => int 75
      123 => int 0

This is actually the first version that provides what we need. We can individually specify the filter and get the result. stuff needs to be extracted from the resulting array and with a PHP function like array_values we can also extract just the values, resetting the keys.

Option 4 - Improving JInput::getArray()

While Option 3 might work well, there are some issues:

  • What if we do not know in advance the name of the fields?
  • What if I have like 100+ fields - I don't want to write each of them

To solve this issues, we need to do it in more steps:

// Get the data unfiltered
$unfilteredData = $app->input->get('stuff', array(), 'ARRAY');

// Pre-filling all parameters with the INT filter.
$a4 = $app->input->getArray(array(
    'stuff' => array_fill_keys(array_flip($unfilteredData), 'INT')
));

Result is:

array (size=1)
  'stuff' => 
    array (size=4)
      'abc' => int 1
      'def' => int 75
      123 => int 0

Possible security issue if you need the keys: we are filtering the values, but not the keys!

Some simple processing:

$finalArray = array_values($a4['stuff']);

array (size=4)
  0 => int 1
  1 => int 75
  2 => int 0

ANSWER IS HERE: -> Complete code to get an array with n-parameters as integers from a POST request (ideally fit this into a method):

// Get the data unfiltered
$unfilteredData = $app->input->get('stuff', array(), 'ARRAY');

// Check to see if array is empty.
if (! empty($unfilteredData))
{
    $a4 = $app->input->getArray(array(
        'stuff' => array_fill_keys(array_flip($unfilteredData), 'INT')
    ));

    $result = array_values($a4['stuff']);
}
else
{
    $result = array();
}
  • 1
    Thanks for the detailed analysis and solution here Valentin. Just to close the loop on this with @JeremyProffitt's comment on creating a system plugin to extend JRequest, I looked at doing that now using your code above and realised I may be missing something. Would the intention of the system plugin be simply to load the new class early in the request processing cycle to make it available to components, or is there some additional 'system plugin' magic that I'm not aware of? Question for both of you really! – John Rix Nov 25 '14 at 0:20
  • I have not looked into building a system plugin for something like this. If you need it in just one extension, I would just put it in a helper class. – Valentin Despa Nov 25 '14 at 7:12
  • I think the code snippet here definitely accomplishes the task. Since this should be written as a method in order to be reusable at all, it makes equal sense to take the extra couple of minutes for the plugin that would make that functionality available globally in JInput. Even that would only be an interim step to the best plan, which would be adding a unit test and submitting the improvement to core. – Jeremy Proffitt Nov 25 '14 at 11:24
  • 1
    I'm still a bit confused as to what the system plugin should actually do in this instance... can you elaborate? Apologies for the dumb question, but I haven't extended core elements of Joomla like JRequest in the past. – John Rix Nov 25 '14 at 13:45
  • @JohnRix: Note that it's actually JInput, as JRequest was deprecated. The system plugin would actually be creating a duplicate version of the JInput library, and loading in place of the core version. That's why you need the system plugin, in order to supplant the original in the autoloader. If you didn't want to go that route, you could write a class that actually extends JInput and would still be housed in a system plugin, but you would call that class going forward instead of JInput. – Jeremy Proffitt Nov 25 '14 at 19:55
7

Joomla does not support multiple type as filters.

This can not be done either using JRequest or JInput.

There is no workaround available in Joomla till now. You need to handle multiple filters in your code only.

4

You're definitely not missing something. If you find that you're doing this regularly, you can create a system plugin to extend the existing JRequest class and add a new filter type to that.

  • 1
    As it stands this is more a comment than an answer. Please provide a blueprint on what steps need to be done, maybe some snippets of code. – Valentin Despa Nov 22 '14 at 10:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.