6

We have the following code in our Application.cfc:

<cffunction name="onError" returnType="void" output="false">
    <cfargument name="exception" required="true">
    <cfargument name="eventname" type="string" required="true">
    <cfset cfcatch = exception>
    <cfinclude template="standalone/errors/error.cfm">
</cffunction>

Within the error.cfm page we have this code (I didn't write it):

<cfscript>
        function GetCurrentURL() {
            var theURL = "http";
            if (cgi.https EQ "on" ) theURL = "#TheURL#s";
            theURL = theURL & "://#cgi.server_name#";
            if(cgi.server_port neq 80) theURL = theURL & ":#cgi.server_port#";
            theURL = theURL & "#cgi.path_info#";
            if(len(cgi.query_string)) theURL = theURL & "?#cgi.query_string#";
            return theURL;  
        }
</cfscript>

This is all part of a script that puts together bunches of details about the error and records it to the database.

When an error occurs, we receive the message "The routine GetCurrentURL has been declared twice in different templates." However, I have searched the entire codebase in several different ways and found "GetCurrentURL" used only twice, both times in error.cfm. The first time is the declaration, and the second is actual use. So I'm not sure why CF is saying "in different templates".

My next thought was that the problem is a recursive call, and that error.cfm is erroring and calling itself, so I attempted these two changes, either of which should have resolved the issue and unmasked the real error:

<cfif StructKeyExists(variables,"GetCurrentURL") IS "NO">
    <cfscript>
            function GetCurrentURL() {
                var theURL = "http";
                if (cgi.https EQ "on" ) theURL = "#TheURL#s";
                theURL = theURL & "://#cgi.server_name#";
                if(cgi.server_port neq 80) theURL = theURL & ":#cgi.server_port#";
                theURL = theURL & "#cgi.path_info#";
                if(len(cgi.query_string)) theURL = theURL & "?#cgi.query_string#";
                return theURL;  
            }
    </cfscript>
</cfif>

And:

<cfscript>
    if (!StructKeyExists(variables,"GetCurrentURL")) {
            function GetCurrentURL() {
                var theURL = "http";
                if (cgi.https EQ "on" ) theURL = "#TheURL#s";
                theURL = theURL & "://#cgi.server_name#";
                if(cgi.server_port neq 80) theURL = theURL & ":#cgi.server_port#";
                theURL = theURL & "#cgi.path_info#";
                if(len(cgi.query_string)) theURL = theURL & "?#cgi.query_string#";
                return theURL;  
            }
    }
</cfscript>

Neither worked. I also tried adding this to the page just before the function call:

<cfoutput>"#StructKeyExists(variables,"GetCurrentURL")#"</cfoutput>

It caused the word "YES" to be printed on screen. This indicates that the above should work, as clearly the contents of the if statement will evaluate to "YES", and thus the if statement will evaluate to false, and thus the function will not be declared, and thus I will retain my sanity. But for some reason this problem persists.

Any thoughts on what might be occuring or how to troubleshoot next? I'm stuck at this point.

James A Mohler
  • 11,060
  • 15
  • 46
  • 72
Nicholas
  • 1,974
  • 4
  • 20
  • 46

3 Answers3

7

ColdFusion still sees the function declaration when it compiles it into bytecode. You can use a cfinclude to include the function declaration:

<cfif StructKeyExists(variables,"GetCurrentURL") IS "NO">
<cfinclude template="udf.cfm" />
</cfif>

Then in the udf.cfm place your function declaration. That should work as you want and prevent CF from throwing the error.

Sean Coyne
  • 3,864
  • 21
  • 24
  • oh yes!! why didn't I see that? It's not enough to parse out the declaration. I bet you are right Sean... nice! – Mark A Kruger Apr 02 '12 at 19:25
  • I ended up resolving this by moving the declarations to Application.cfc, but that involves some negative repurcussions. Initial testing locally indicates that your solution seems to work much better, so I'll work on getting that QAed and into prod. Thank you so much! :) – Nicholas Apr 02 '12 at 19:35
0

Another solution is to delete the function from scope before the definition. For example...

<cfset StructDelete(variables,'myFunction')>
<cffunction name="myFunction">...</cffunction>
Ben Cameron
  • 4,335
  • 6
  • 51
  • 77
  • Welcome to SO Marius, can you describe where, how and why deleting the OP's function would solve the problem? – CPHPython Jan 19 '17 at 13:31
  • As mentioned in @SeanCoyne's answer, the problem is that the routine declaration error doesn't happen at runtime -- it happens at compile time. That means deleting the function from the `variables` scope doesn't do anything to fix the problem. While @MariusMaxeiner's approach would work to remove an unwanted function, you couldn't use it to prevent the compile error. – tobylaroni Sep 04 '19 at 12:19
0

ColdFusion also lets you instantiate the same cfc that has the function(s) more than once. In wwwroot/x.cfc

<cfcomponent>
    <cffunction name="fMy">
        <cfreturn "some data">
    </cffunction>
</cfcomponent>

In wwwroot/y.cfm

<cfset oFcns = createObject("component","x")>
<cfset oFcns = createObject("component","x")>
<cfset z = oFcns.fMy()>

Outputs:

some data

The createObject could have been run multiple times by a loop. Point is the second instantiation doesn't bomb.

gordon
  • 1,152
  • 1
  • 12
  • 18