2

得到一些我无法解决的非常奇怪的东西。

我在 CFC (guest.cfc) 中有 3 种方法:

- save
- create
- update

我将 argumentCollection 传递给 save 方法。

saveGuest = objGuest.save(argumentcollection=guestStruct)

如果它包含一个 Identier,则将 argumentCollecion 传递给 update 方法,如果不包含,则将集合传递给 create 方法。

当从应用程序中的一个地方调用时,这工作正常,但是当我创建对 save 方法的新调用时,create 方法工作正常,但是如果在 update 方法中传递了一个 ID,我会收到一个错误,即 UPDATE变量不存在。

但是,如果我通过创建 cfc 的对象来改变我调用它的方式,它会起作用..

所以..

saveObject =  update(argumentCollection = arguments;

不工作。收到更新变量不存在的错误。

saveObject =  createObject("component",'guest').update(argumentCollection = arguments);

确实有效。

请注意,这两个调用都发生在 guest.cfc 本身内。

当我将表单结构传递给 save 方法时不会发生此问题,但当我将标准结构(从 XML 导入构造)传递给它时会发生。

很奇怪。

有人对可能导致这种情况的原因有任何想法吗?


编辑 4 月 24 日 - 为 guest.cfc 添加了代码


<cffunction name="save" output="false" access="remote" hint="save guest">
    <cfargument name="title" type="any" required="false" default="" />
    <cfargument name="first_name" type="any" required="false" default="" />
    <cfargument name="surname" type="any" required="false" default="" />
    <cfargument name="dob" type="any" required="false" default="NULL" />
    <cfargument name="partner_first_name" type="any" required="false" default="" />
    <cfargument name="partner_surname" type="any" required="false" default="" />
    <cfargument name="partner_dob" type="any" required="false" default="NULL" />
    <cfargument name="address_1" type="any" required="false" default="" />
    <cfargument name="address_2" type="any" required="false" default="" />
    <cfargument name="address_3" type="any" required="false" default="" />
    <cfargument name="city" type="any" required="false" default="" />
    <cfargument name="state" type="any" required="false" default="" />
    <cfargument name="postcode" type="any" required="false" default="" />
    <cfargument name="country" type="any" required="false" default="" />
    <cfargument name="phone_bh" type="any" required="false" default="" />
    <cfargument name="phone_ah" type="any" required="false" default="" />
    <cfargument name="phone_mob" type="any" required="false" default="" />
    <cfargument name="fax" type="any" required="false" default="" />
    <cfargument name="email" type="any" required="false" default="" />
    <cfargument name="business" type="any" required="false" default="" />
    <cfargument name="notes" type="any" required="false" default="" />
    <cfargument name="referer" type="any" required="false" default="" />
    <cfargument name="prospect" type="any" required="false" default="" />
    <cfargument name="occasion" type="any" required="false" default="" />
    <cfargument name="occasion_date" type="any" required="false" default="NULL" />


    <!---pass to Create or Save--->
    <cfif NOT isdefined("arguments.guest_id") OR arguments.guest_id EQ "0">
        <cfset saveObject =  create(argumentCollection = arguments) />
    <cfelse>
        <cfset saveObject =  update(argumentCollection = arguments) />
    </cfif>

    <cfreturn saveObject>

</cffunction>


<!---CREATE--->
<cffunction name="create" output="false" access="private" returntype="struct" hint="Create a New Item">
    <cfargument name="provider_id" type="any" required="false" default="#session.providerID#" />
    <cfargument name="ext_ref_id" type="any" required="false" default="NULL" />
    <cfargument name="tstamp" type="any" required="false" default="#session.tStamp#" />

    <cfif isValid('date',arguments.occasion_date)>
        <cfset iOccasionDate = createODBCDateTime(arguments.occasion_date)>
    <cfelse>
        <cfset iOccasionDate = "NULL">
    </cfif>

    <cfset returnStruct = StructNew()>

    <cfquery name="insertGuest" datasource="#Application.ds#">
        INSERT INTO guest (provider_id, ext_ref_id, title, first_name, surname, full_name, partner_first_name, partner_surname, partner_full_name, address_1, address_2, address_3, city, state, postcode, country, phone_bh, phone_ah, phone_mob, fax, email, company, notes, referer, prospect, occasion, occasion_date, tstamp)
        VALUES (#provider_id#, #ext_ref_id#, '#arguments.title#', '#arguments.first_name#', '#arguments.surname#', '#arguments.first_name# #arguments.surname#', '#arguments.partner_first_name#', '#arguments.partner_surname#', '#arguments.partner_first_name# #arguments.partner_surname#', '#arguments.address_1#', '#arguments.address_2#', '#arguments.address_3#', '#arguments.city#', '#arguments.state#', '#arguments.postcode#', '#arguments.country#', '#arguments.phone_bh#', '#arguments.phone_ah#', '#arguments.phone_mob#', '#arguments.fax#', '#arguments.email#', '#arguments.company#', '#arguments.notes#', '#arguments.referer#', '#arguments.prospect#', '#arguments.occasion#', #iOccasionDate#, #CreateODBCDateTime(tstamp)#)
    </cfquery>

    <cfquery name="guest" datasource="#Application.ds#">
        SELECT max(guest_id) as id
        FROM guest
        WHERE provider_id = #provider_id#
    </cfquery>

    <cfset returnStruct.id = #guest.id#>
    <cfreturn returnStruct>

</cffunction>



<!---UPDATE--->
<cffunction name="update" output="false" access="private" returntype="struct" hint="Update an existing item">

    <!---general details--->
    <cfquery name="update" datasource="#Application.ds#">
        UPDATE guest
        SET provider_id = provider_id

            <cfif isdefined("arguments.title")>
                ,title = '#arguments.title#'
            </cfif>
            <cfif isdefined("arguments.first_name")>
                ,first_name = '#arguments.first_name#'
            </cfif>
            <cfif isdefined("arguments.surname")>
                ,surname = '#arguments.surname#'
            </cfif>
            <cfif isdefined("arguments.full_name")>
                ,full_name = '#arguments.full_name#'
            </cfif>
            <cfif isdefined("arguments.dob")>
                ,dob = #formDate2odbcDate(arguments.dob)#
            </cfif>

            <cfif isdefined("arguments.partner_first_name")>
                ,partner_first_name = '#arguments.partner_first_name#'
            </cfif>
            <cfif isdefined("arguments.partner_surname")>
                ,partner_surname = '#arguments.partner_surname#'
            </cfif>
            <cfif isdefined("arguments.partner_full_name")>
                ,partner_full_name = '#arguments.partner_full_name#'
            </cfif>
            <cfif isdefined("arguments.partner_dob")>
                ,partner_dob = #formDate2odbcDate(arguments.partner_dob)#
            </cfif>

            <cfif isdefined("arguments.address_1")>
                ,address_1 = '#arguments.address_1#'
            </cfif>
            <cfif isdefined("arguments.address_2")>
                ,address_2 = '#arguments.address_2#'
            </cfif>
            <cfif isdefined("arguments.address_3")>
                ,address_3 = '#arguments.address_3#'
            </cfif>
            <cfif isdefined("arguments.city")>
                ,city = '#arguments.city#'
            </cfif>
            <cfif isdefined("arguments.state")>
                ,state = '#arguments.state#'
            </cfif>
            <cfif isdefined("arguments.postcode")>
                ,postcode = '#arguments.postcode#'
            </cfif>
            <cfif isdefined("arguments.country")>
                ,country = '#arguments.country#'
            </cfif>
            <cfif isdefined("arguments.phone_bh")>
                ,phone_bh = '#arguments.phone_bh#'
            </cfif>
            <cfif isdefined("arguments.phone_ah")>
                ,phone_ah = '#arguments.phone_ah#'
            </cfif>
            <cfif isdefined("arguments.phone_mob")>
                ,phone_mob = '#arguments.phone_mob#'
            </cfif>
            <cfif isdefined("arguments.fax")>
                ,fax = '#arguments.fax#'
            </cfif>
            <cfif isdefined("arguments.email")>
                ,email = '#arguments.email#'
            </cfif>
            <cfif isdefined("arguments.subscribe_email_broadcast")>
                ,subscribe_email_broadcast = '#arguments.subscribe_email_broadcast#'
            </cfif>
            <cfif isdefined("arguments.company")>
                ,company = '#arguments.company#'
            </cfif>
            <cfif isdefined("arguments.notes")>
                ,notes = '#arguments.notes#'
            </cfif>
            <cfif isdefined("arguments.prospect")>
                ,prospect = '#arguments.prospect#'
            </cfif>
            <cfif isdefined("arguments.occasion")>
                ,occasion = '#arguments.occasion#'
            </cfif>
            <cfif isdefined("arguments.occasion_date")>
                ,occasion_date = #formDate2odbcDate(arguments.occasion_date)#
            </cfif>

        WHERE guest_id = #arguments.guest_id#
    </cfquery>

    <cfset returnStruct = structNew()>
    <cfset returnStruct.id = arguments.guest_id>
    <cfreturn returnStruct>

</cffunction>

4

2 回答 2

2

如果没有 CFC 代码和调用代码的示例,要更精确有点困难,但是我倾向于建议您检查组件的 init()。你有一个 init() 方法,你在调用它吗?例如,组件定义的大纲

<cfcomponent>

    <cffunction name="init" access="public">
        <cfreturn this>
    </cffunction>

    <cffunction name="save" access="public">
        <!--- logic --->
    </cffunction>

    <cffunction name="create" access="public">
        <!--- logic --->
    </cffunction>

    <cffunction name="update" access="public">
        <!--- logic --->
    </cffunction>

</cfcomponent>

这将由以下任一调用

<cfscript>
    // This will work in CF9 upwards
    objCFC = new guest(/* add any arguments you have in the init() method here */);
    objCFC.update(......);

    // This also works
    objCFC = CreateObject('component','guest').init(/* add any arguments you have in the init() method here */);
    objCFC.update(......);
</cfscript>

按照您的示例进行编辑

那个CFC很讨厌。有各种明显的问题。

  1. 您依赖于 CFC 内的应用程序/会话范围,从而迫使它依赖全局变量。这就是 init() 方法的用途,您可以init(datasource, provider_id, ext_ref_id, tstamp)将它们存储在variables.范围内,因此它将不再容易受到 CFC 之外未定义的变量的影响
  2. 您正在使用大量的 VARCHAR 字段,没有任何转义,而 cfc 允许远程访问。这很容易受到 SQL 注入的影响。Bobby Tables 先生可以告诉你为什么这很糟糕(http://bobby-tables.com/
  3. 您继续使用字符串值 NULL。如果将其传递到 varchar/quotes 内的数据库中,则它将存储为“NULL”而不是数据库 NULL 值

总而言之,最好的做法是重写这个组件。任何使用该组件的代码更改都将是最小的,以至于必须添加 init() 并且可能会删除一些参数,但是您会发现它的稳定性得到了改善,并且一切顺利,这个奇怪的问题将消失。

于 2012-04-17T08:28:39.983 回答
2

在 CF 中,当您在函数内部编写类似的内容时<cfset iOccasionDate = ... >,您正在该 CFC/模板的全局变量范围内<cfquery name="insertGuest" ...>创建这些内容。

您需要编写<cfset var iOccasionDate = ... ><cfset local.iOccasionDate = ... ><cfquery name="local.insertGuest" ...>以确保它们是在函数的局部变量范围内创建的,并且不要覆盖其他变量。


你的具体问题是因为你有这个:

<cfquery name="update" datasource="#Application.ds#">

因此,您正在使用更新查询覆盖您的更新功能。


需要注意的一些快速事项:

  • 本地作用域适用于 CF9 及更高版本。如果您在 CF8 或以下,则需要通过<cfset var local = StructNew() />在函数顶部编写来模仿它。

  • 如果您使用RailoOpenBD,则有一些设置可以将默认行为更改为始终在本地范围内创建(这避免了对 var/local 范围的需要),但 ACF 没有此选项(还没有?)

  • 使用 cfqueryparam!- 西蒙已经提到了这一点,但它的重要性足以重复。您应该始终根据数据的使用位置来处理数据——以防止有意和意外的注入攻击——对于 cfquery,这意味着使用 cfqueryparam。

于 2012-04-24T13:54:05.163 回答