Skip to content

Conversation

jenswittmann
Copy link
Contributor

This solves a PHP fatal error that occurs when using something like this:

[[!#SESSION.user.password:trim]]

PHP Error

Fatal error: Uncaught TypeError: trim(): Argument #1 ($string) must be of type string, array given in core/src/Revolution/Filters/modOutputFilter.php:66 Stack trace: #0 core/src/Revolution/Filters/modOutputFilter.php(66): trim(Array) #1 core/src/Revolution/modTag.php(354): MODX\Revolution\Filters\modOutputFilter->filter(Object(ModxPro\PdoTools\Parsing\Tag)) #2 core/components/pdotools/src/Parsing/Tag.php(32): MODX\Revolution\modTag->filterOutput() #3 core/components/pdotools/src/Parsing/Parser.php(264): ModxPro\PdoTools\Parsing\Tag->process() #4 core/src/Revolution/modParser.php(221): ModxPro\PdoTools\Parsing\Parser->processTag(Array, true) #5 core/components/pdotools/src/Parsing/Parser.php(73): MODX\Revolution\modParser->processElementTags('', '<!DOCTYPE html>...', true, false, '[[', ']]', Array, 9) #6 core/src/Revolution/modResource.php(520): ModxPro\PdoTools\Parsing\Parser->processElementTags('', '<!DOCTYPE html>...', true, false, '[[', ']]', Array, 10) #7 core/src/Revolution/modResource.php(468): MODX\Revolution\modResource->parseContent() #8 core/src/Revolution/modResponse.php(72): MODX\Revolution\modResource->prepare() #9 core/src/Revolution/modRequest.php(154): MODX\Revolution\modResponse->outputContent(Array) #10 core/src/Revolution/modRequest.php(138): MODX\Revolution\modRequest->prepareResponse() #11 core/src/Revolution/modX.php(1509): MODX\Revolution\modRequest->handleRequest() #12 index.php(63): MODX\Revolution\modX->handleRequest() #13 {main} thrown in core/src/Revolution/Filters/modOutputFilter.php on line 66

System

  • MODX 3.1.2
  • PHP Version 8.3.21
  • Extras: pdoTools 3.0.2-pl

@rthrash
Copy link
Member

rthrash commented Jul 11, 2025

@jenswittmann does that happen outside of pdotools?

@opengeek opengeek changed the title [3.1.2] bugfix trim() fatale error in modOutputFilter.php Fix fatal error in trim output filter Jul 11, 2025
@jenswittmann
Copy link
Contributor Author

@jenswittmann does that happen outside of pdotools?

Yes, you can try this with a Snippet that return an Array:

<?php

return [
    'demo' => 'test'
];

When you use [[demo:trim]] the error occurs.

@@ -63,7 +63,7 @@ public function filter(&$element)

$this->log('Processing Modifier: ' . $m_cmd . ' (parameters: ' . $m_val . ')');

$output = trim($output);
$output = trim((string) $output);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather see the solution test for string rather than cast all values to that type. If I'm not mistaken, there would be legitimate cases where the value being worked with is not a string (e.g., int or bool, etc.), so maybe this:

Suggested change
$output = trim((string) $output);
$output = is_string($output) ? trim($output) : $output;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be argued that all output filters should be operating only on strings. Perhaps it is worth looking at bypassing filtering altogether if the value is not a string?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so; what about the comparison filters (gt, lt, etc.) acting on the integer output of a snippet? The number TV, as it stands, does only output a string representation. But with that TV type I could see there being an input option to force an integer, or a new filter that acts on a strict comparison. I think it just keeps your options (so to speak) open if you don't coerce values passed to the filter to string. That's my 2¢ at least ;-)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I rephrase this to say scalar value, would you agree? Though technically, all elements in MODX that appear in content HAVE to return a string to be useful. You can obviously create snippets that return other (non-scalar) types in situations where you are using that snippet programmatically in PHP code, but when used in content, it is essentially useless. Since output filters are meant to act on the value returned to be used in content, I think my point is valid.

Copy link
Collaborator

@smg6511 smg6511 Jul 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, definitely agree with bypassing non-scalar vals. So maybe at the top of the filter method, add this:

if (!is_scalar($element->_output)) {
    return;
}

Then still test for string to trim instead of coercing as I suggested above?

@jenswittmann
Copy link
Contributor Author

@smg6511 here's a real-world example that might not work with the discussed fix maybe 🤔

Check if the user has a name in a custom session variable and output a link based on it:

[[!#SESSION.user.password:is=``:then=`<a href="/login">Login</a>`:else=`<a href="/login?logout=true">Logout</a>`]]

Every output modifier gets trimmed in line 66. So, with return, you always get the else value, right?

@smg6511
Copy link
Collaborator

smg6511 commented Jul 15, 2025

@jenswittmann - No, I did some tests with [[#!GET.somekey:trim:is=...]] in various ways and it works like you want it to with the early return. The benefit of the early return is that if you happen to unintentionally apply filters on an array, using [[#GET:trim:is=...]] for example, you'll just get back a string representation of the array (or just "Array"). Otherwise you would get the else value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants