Search code examples
functioncoldfusioncfmlremoving-whitespacelucee

Why does Lucee prepend a leading space character when I directly output values returned from a <cffunction> and how do I stop it?


I'm having a very strange issue with output from a function. I have a basic function for sanitizing user inputs. When I try to output the function result I get the value prepended with a space. If I assign the function result to a variable and then output that variable, the space is not present. Here's an example of what I'm talking about. Imagine there is a function called fn_SanitizeInput().

<cfset var_UserInput = "foo">
<cfset var_SanitizedUserInput = fn_SanitizeInput(var_UserInput)>  // foo

<cfoutput>

    Input Length: #len(var_UserInput)#          // 3
    Sanitized Input Length:
        #len(fn_SanitizeInput(var_UserInput))#  // 3
        #len(var_SanitizedUserInput)#           // 3

    Function Output: |#fn_SanitizeInput(var_UserInput)#|                // | foo|
    Trimmed Function Output: |#trim(fn_SanitizeInput(var_UserInput))#|  // | foo|
    Var Output: |#var_SanitizedUserInput#|                              // |foo|

</cfoutput>

I don't understand why the len() function returns 3, but four characters are displayed when I print the result. And since trimming the function still gives me the leading space, I feel like the function result is correct and that Lucee is adding the space for some unknown reason when it performs the evaluation. Has anyone else run into this? I can just assign all the results to a variable first if I need to, but I'd still like to know why this is happening.


Solution

  • Short answer

    Change

    <cffunction name="fn_SanitizeInput">
        <cfargument name="arg">
        <cfreturn arguments.arg>
    </cffunction>
    

    To

    <cffunction name="fn_SanitizeInput" output="false">
        <cfargument name="arg">
        <cfreturn arguments.arg>
    </cffunction>
    

    Longer answer

    Where did the space come from?

    The space is from the end of <argument> tag to the start of the <cfreturn> tag. If you really wanted to, you could

    <cffunction name="fn_SanitizeInput"><cfargument name="arg"><cfreturn arguments.arg></cffunction>
    

    The code you wrote may have looked like:

    #len(fn_SanitizeInput(var_UserInput))#
    

    But in reality, it was something like this:

     <cfsavecontent var="result">#fn_SanitizeInput(var_UserInput)#</cfsavecontent>
    
     #len(result)#
    

    Some editorializing

    I really wish the cfml default output mode for functions was silent, but alas it is not. For my own sanity, I set output="false" so I don't have to worry about it.