【问题标题】:How to insert date from a coldfusion variable to a sql field?如何将coldfusion变量中的日期插入sql字段?
【发布时间】:2014-11-02 20:44:46
【问题描述】:

由于不寻常的代码设置,我没有使用带有 cfparam 标记的 cfquery,而是构建了一个 sqlInsertCols 列表和一个 sqlInsertValues 列表,并在插入语句中使用它们。代码如下:

<cfscript>
   var sqlInsertCols = "";
   var sqlInsertValues = "";
   // some looping and other processing here to fill the lists
   ...
</cfscript>

<cfquery datasource="..." name="insert">
   INSERT INTO MyTable(#sqlInsertACols#)
   VALUES (#sqlInsertVals#)
</cfquery>

首先,考虑到这两个 sql 字符串都填充在此代码中,而不是基于任何用户输入,这是否存在任何安全问题?

这适用于我插入的几个字段,但我只是尝试添加一个日期字段并且无法让插入工作。日期格式为“mm/dd/yyyy”。将日期添加到 sql 列表的代码:

sqlInsertCols = ListAppend(sqlInsertCols, "MyDateField");
sqlInsertValues = ListAppend(sqlInsertValues, myDateVar);

这运行没有错误,但数据库中的值为1900-01-01 00:00:00.000

我尝试在日期前后添加引号,但似乎无法正确插入。有没有办法做到这一点?

【问题讨论】:

  • 试试sqlInsertValues = ListAppend(sqlInsertValues, CreateODBCDateTime(myDateVar));
  • @xpa1492 - 成功了!谢谢!如果您将其发布为答案,我会接受它
  • 比@xpa1492 的建议更有效的是首先创建日期变量而不是然后转换的字符串变量。
  • 不基于任何用户输入 究竟来源是什么?如果这些数据来自数据库中的另一个表,为什么不直接使用 INSERT INTO/SELECT 呢?否则,代码可能仍然存在 sql 注入的风险。另外,为什么不使用 cfquery 的 cfscript 版本呢?然后您可以使用 cfqueryparam 并获得绑定变量的性能优势。
  • @DanBracuk - 我们将日期作为字符串获取。它是从网页上抓取的。

标签: sql sql-server datetime coldfusion


【解决方案1】:

SQL Sever 在日期周围使用单引号。你试过那些吗?

【讨论】:

  • 我试过了,但是 CF 似乎在插入语句中将它们翻译成双引号,然后它会导致错误。
  • @froadie:你需要使用preserveSingleQuotes() 函数。
  • SQL Sever 在日期周围使用单引号 不完全正确。字符串文字需要引号。在这种情况下,日期字符串。根据目标列,该字符串可能被隐式转换为date/time,但它仍然是一个字符串。 @froadie - 引号加倍的原因是 CF 的安全功能。不使用 cfqueryparam 的查询存在 sql 注入的风险,因此 CF 会自动加倍引号以防止这种情况发生。 preserveSingleQuotes 逆转了这种行为,但这样做将您的数据库暴露给 CF 试图阻止的事情。所以请谨慎使用。
  • 加 1 让 Eric 的声誉高到足以发布 cmets。
【解决方案2】:

首先让我说我根本不喜欢这种方法。您似乎正在尝试将 cfquery 用作通用包装器 - 一种“插入”变量列表的方法。这会使您的查询被其他代码掩盖。鉴于查询是最容易受到攻击的向量,更不用说通常包含用户输入,这使得所有事情都更难排除故障。此外,cfquery 是 CF 语言的一个强项 - 您可以从 DB IDE 剪切和粘贴并简单更改变量输入(当然添加 cfqueryparam)的少数语言之一。

最后,您的查询需要 cfqueryparam 来保护免受 SQLi 的影响——所以在回答你问题的最后一部分时——是的,这段代码很容易受到攻击。很少有不使用 cfqueryparam 的情况。

所以...这里有一个解决方案(同样,我不喜欢或不推荐 :),您可以将其用作起点:

<cfscript>
   var sqlInsertCols = "";
   var sqlInsertValues = "";
   // some looping and other processing here to fill the lists
   ...
</cfscript>

<cfquery datasource="..." name="insert">
   INSERT INTO MyTable(#sqlInsertACols#)
   VALUES (
    <cfloop list="#sqlinsertValues#" index="colVal">
        <cfif isDate(colVal)>
            <Cfqueryparam cfsqltype="CF_SQL_DATE" value="#colval#"/>
        <cfelse>
            <cfqueryparam cfsqltype="CF_SQL_CHAR" value="#colval#"/>
        </cfif>
    <cfif colVal IS NOT listlast(sqlInsertValues)>
              ,
       </cfif>
    </cfloop>

   )
</cfquery>

这假定将标识为日期的字段插入到“日期”类型的数据库中的列中。它还假设所有“其他”非日期字段都是字符字段。您可能需要为数字或整数或数据中的任何内容添加检查。

此外,如果您需要根据值检查列名,您可以使用 listgetat,如下所示:

<cfscript>
   var sqlInsertCols = "";
   var sqlInsertValues = "";
   // some looping and other processing here to fill the lists
   ...
</cfscript>

<cfquery datasource="..." name="insert">
   INSERT INTO MyTable(#sqlInsertACols#)
   VALUES (
    <cfloop from="1" to="#listlen(sqlinsertValues)#" index="x">
        <cfif listgetat(sqlInsertCols,x) IS 'dateadded'>
            <Cfqueryparam cfsqltype="CF_SQL_DATE" value="#listgetat(sqlInsertValues,x)#"/>
        <cfelseif listgetat(sqlInsertCols,x) IS 'userid'>>
            <cfqueryparam cfsqltype="CF_SQL_INTEGER" value="#listgetat(sqlInsertValues,x)#"/>
        </cfif>

       <cfif x IS NOT listlen(sqlInsertValues)>
            ,
          </cfif>

    </cfloop>
   )
</cfquery>

最后,对于完全不推荐的又快又脏的解决方案,你可以试试这个:

<cfscript>
   var sqlInsertCols = "";
   var sqlInsertValues = "";
   // some looping and other processing here to fill the lists
   ...
</cfscript>

<cfquery datasource="..." name="insert">
   INSERT INTO MyTable(#sqlInsertACols#)
   VALUES (
    <cfloop list="#sqlinsertValues#" index="colVal">

        '#colval#'
            <cfif colVal IS NOT listlast(sqlInsertValues)>
                  ,
           </cfif>
    </cfloop>

   )
</cfquery>

这可能是因为您的 RDBMS 隐式转换 - 在许多/大多数情况下,它可以从字符转换为日期、整数或数字。当然,您也可能很容易遇到语法错误。

最后一点:上面的第一个和第三个示例使用一些简单的方法在列表中插入逗号 - 将值与列表中的最后一个值进行比较,如果不匹配则插入。所以这假设列表中不是最后一个的任何项目与列表中的最后一个项目不同。如果最后一项在查询中的其他地方重复,那么您将收到缺少逗号的语法错误。祝你好运!

勘误表: 仅供参考 - 在最后一个 sn-p - 变量外部的单引号不会被 CFQUERY 转义 .. 所以当你使用 '#varName#' 时 - 单引号被保留,但是当它们在变量内时它们被转义 - 因为CF 自然地假设(并且最佳实践要求)您正在处理要以可变形式插入的 内容,而不是查询语言本身。

【讨论】:

  • 感谢您的详细解答。其中一些非常有用。我将在某种程度上重组我的做法(我将为列名提供一种“查找”结构,以便我可以根据 html 提取它,但它仍然受到控制)。我可能会在循环中使用 cfqueryparams。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多