【问题标题】:ColdFusion - String to variableColdFusion - 字符串到变量
【发布时间】:2019-09-12 13:37:08
【问题描述】:

我有一个从数据库中得到的这样的字符串:

user=me@example.com&name=John

我想知道是否有一种简单的方法可以提取数据并将它们放入两个变量中,用户和名称。

【问题讨论】:

  • 您可以使用正则表达式或查看与其他字符串函数配对的SpanExcludinghelpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions/…
  • 将字符串视为嵌套列表。外部列表由& 字符分隔,内部列表由= 字符分隔。
  • 由于这显然是一个 URL 参数字符串,您是否在将其插入数据库之前对其进行编码或清理?还是像上面一样存储?
  • @Shawn 说了什么。这是攻击您网站的一种非常简单的方法。

标签: coldfusion cfml


【解决方案1】:

@Marc,根据@Dan Bracuk 的建议,您可以先使用提到的分隔符将字符串拆分为&,然后再使用=。请参考我的以下代码,这将对您有所帮助。我希望。

Runnable Example

<cfset yourInput= 'user=me@example.com&name=John'>
<!--- Get the first value. I mean "user" part --->
<cfset splitFirstPart = listfirst(yourInput,'&', true)>
<cfset splitLastPart = listlast(yourInput, '&', true)>
<!--- Get the second part value --->
<!--- Above values are split by using & --->
<cfset user = listlast(splitFirstPart, '=', true)>
<Cfset name = listlast(splitLastPart, '=', true)>
<!--- 
    Now we can again split the list by using =. 
    Now you can see the result.
--->
<cfoutput>
    User : #user# <br/>
    Name : #name#
</cfoutput>

如果您需要任何其他 CFML 功能和说明,请参考https://cfdocs.org/

谢谢。

【讨论】:

  • 需要注意的是,如果参数值为空,listLast() 将返回 first 元素。例如&amp;name=(blank)。要使代码更健壮,请考虑改用getToken() 函数。 @MarcElBichon - 此外,您可以轻松地将上面的代码转换为可重用的函数,该函数拆分任何查询字符串并返回参数和值的结构
  • 是的@ageax。然后可以在listlast() 中使用includeEmptyValues 属性。例如 listlast(splitFirstPart,'=',true)。然后它将仅返回 user = '' (empty)。请检查一下。
  • 是的。大多数列表函数很长时间都不支持该属性,我一直忘记他们最终“修复”了它们!希望您不介意我在上面的代码中添加了您的建议,因为 url 参数很可能为空 :-) 如果您不喜欢它,请随时回滚。
  • 我希望所有的列表函数都支持 includeEmptyValues 属性。特别是 listfirst 和 last 支持。我交叉检查。感谢您对我的 cmets 所做的更改。 @ageax。
  • 感谢您的宝贵时间@Ageax
【解决方案2】:

这是我对如何解决这个问题的看法。

我喜欢将结构作为最终结果。我也喜欢将每个函数用作隐式循环。

<cfscript>
yourInput= 'user=me@example.com&name=John';

variables.result = {};
ListEach(yourInput,
   function(item) { variables.result[listfirst(item, "=")] = listLast(item, "="); },
   "&");

writedump(result);
</cfscript>

【讨论】:

  • 简洁明了。我建议的唯一改进是使用includeEmptyElements=true,以防值为空,因此列表函数不会返回“名称”而不是“值”。
【解决方案3】:

为了给未来的读者添加这个答案,有几种方法可以让这个答案更有活力。

本质上,您只是对分隔列表进行两次解析并取出您需要的部分。 ColdFusion 提供了几种方法来做到这一点。

为了说明,我已添加到原始字符串中。

string="user=me@example.com&name=John&somethingelse=42&foo&base64Msg=QmVFeGNlbGxlbnRUb0VhY2hPdGhlcg==" ;

我首选的解析方法是一个 CF 函数,它返回一个包含我需要的所有部分的结构。

public Struct function parseURLParamString( required String inURLStr ) {
    /// Initialize the return struct.
    var retStruct = {} ;
    // Use listEach() function to iterate over the list with delim "&"
    arguments.inURLStr.listeach( 
        function(item){ 
          // listFirst gets 1st list element. listRest() gets all but 1st element. Delim "="
          retStruct[listFirst(item,"=")] = listRest(item,"=") ; 
        }
        , "&"
    ) ;

    return retStruct ;
}

writeDump( parseURLParamString(string) ) ;

这将返回:

然后您可以从返回的结构中引用您需要的变量。

但如果您需要创建实际变量而不是从结构中提取它们,您可以这样做:

arguments.inURLStr.listeach( 
    function(item){ 
      variables[listFirst(item,'=')] = listRest(item,"=") ;
    }
    , "&"
) ;

... 然后将您的外部函数更改为返回 Void 或不返回任何内容并从中删除结构。您可以引用user = #user# 等变量。这需要您提前知道变量,而在传递特定结构时,您可以循环遍历结构并输出键/值。从技术上讲,您还可以循环 variables 范围,但其中可能还有很多其他变量。

如果您愿意,您也可以使用getToken(),但它与listLast() 具有相同的限制。如果您的 value 包含第二个分隔符文本(如填充的 Base64 字符串),那么这些字符将被视为分隔符并被排除在您的值之外。对于base64Msg = QmVFeGNlbGxlbnRUb0VhY2hPdGhlcg==getToken()/listLast() 将返回QmVFeGNlbGxlbnRUb0VhY2hPdGhlcg,其中listRest() 将返回QmVFeGNlbGxlbnRUb0VhY2hPdGhlcg==。或者更糟糕的是,如果字符在字符串的中间,它会被截断。 ListLast() 删除分隔列表的第一项并返回列表的其余部分,因此如果您的字符串包含分隔符,它将返回完整值。

最后,由于这似乎是来自 URL 的字符串,您可能希望在将字符串存储到数据库之前对其进行清理和编码。

如果您保存编码值,它可能会将您的分隔符转换为其编码值。上面的函数只支持单字符分隔符,所以不能像上面那样使用(除非在发送到拆分函数之前解码)。 listToArray 允许使用多字符分隔符。所以这可能是拆分它们的一种方法。

最后,有很多字符可以作为 URL 字符串,#= 这两个肯定会在没有编码和正确处理的情况下导致您出现问题。

【讨论】:

  • 好收获! Base64 编码值。又一个问题。
【解决方案4】:

您可以使用“ListToArray”,使用“&”作为分隔符来拆分每个值,然后再次使用(如果只有 2 个值,则使用 ListFirst 和 ListLast)但是这次使用“=”作为分隔符,这样你将有 ["user=me@example.com", "name=John"] 作为第一个结果,并且 [[[user],[me@example.com]],[[name],[John]]] 作为第二个。

我通常建议使用结构而不是简单的变量,这里举一个例子

<cfscript>
    /* My Raw string */
    MyString = "user=me@example.com&name=John";

    /* Breaking my single string in multiple values */
    MyArrayOfValues = ListToArray(MyString, "&");

    /* Creating my struct o hold my values */
    MyStruct = StructNew();

    /* Interating over my values */
    for (Value in MyArrayOfValues){
        // First Interaction will be: user=me@example.com and the second will be name=John and etc...
        /* Get My attribute name */
        MyAttributeName = ListFirst(Value, "=");
        /* Get My attribute value */
        MyAttributeValue = ListLast(Value, "=");
        /* Evaluate the values of you borth variables and asign each other */
        Evaluate("MyStruct.#LCase(MyAttributeName)# = '#MyAttributeValue#'");
    }
    /* Here you can see your value printed as struct formed by 2 atributes, name and user, both in lower case */
    writeDump(MyStruct);

    /* Here one example how to use this data */
    writeOutput("
        Hi my name is #MyStruct.name# and my user is #MyStruct.user#!
    ");
</cfscript>

这种方法是更通用的方法,因为您的数据库中可能会有更多列,甚至可以将它与来自另一个数据库的其他数据一起使用,始终遵循相同的结构......值由 & 分隔,属性和值由=

【讨论】:

  • 我的投票只是将您的声誉提高到四位数。你欠我一杯啤酒。
  • 虽然不需要评估。只需使用结构符号。另外,不要忘记使用列表函数考虑空参数。
  • 问题是,数据库中的值是动态的,所以他无法知道是否在多个数据库中使用这个算法......因为我使用 Evaluate,我不只是使用类似的东西(MyStruct.#SomeValue#) 工作一下,大概会提示Sintax错误
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-11
  • 2018-03-06
  • 1970-01-01
  • 1970-01-01
  • 2021-04-21
相关资源
最近更新 更多