3

I have an cfmail function set-up in a particular file, email_output.cfm, which requires an ID passed to it to work properly, like email_output.cfm?ID=1. I want to set up a cron job that runs through a query returning the various needed IDs to pass. In testing, I can do the following:

  <cflocation url="email_output.cfm?ID=10" >

But, since cflocation stops all other execution and opens another page, I can't loop through it. How would I pass parameters from a query to a single CF page multiple times?

Thanks - Joe

Joe Lowery
  • 562
  • 11
  • 26
  • 1
    This is an ideal function for a custom tag. Instead of url.id, you'd call attributes.id. It could also be written as a udf. – Regular Jo Oct 13 '14 at 14:54
  • I think I see what you mean about using a custom tag, but don't understand how the parameter would be passed. Would it be something like ``? A specific example would be greatly appreciated. – Joe Lowery Oct 13 '14 at 15:30
  • Check my answer with a sample I just added. – Regular Jo Oct 13 '14 at 15:38

2 Answers2

2

A custom tag sample implementation of this...

If this is your first time using a custom tag, it's easiest to put it in the same folder as the page calling it. There are a few options for putting it in a different directory, but let's start simple.

EmailMembers.cfm

<cfquery name="GetUIDs">
  select userid from users
</cfquery>

<cfoutput query="GetUIDs">
  <cf_maileach uid="#userID#">
</cfoutput>

Notice how I called my tag cf_maileach?

In the same directory, place maileach.cfm, see how the names match?

maileach.cfm

<cfif StructKeyExists(attributes,"uid") and val(attributes.uid) gt 0>
  <cfquery name="getinfo">
    select fname,lname,email
      from users
     where userID = <cfqueryparam cfsqltype="cf_sql_integer" value="#attributes.uid#">
  </cfquery>

  <cfmail to="#getinfo.email#" subject="Hi #getinfo.fname#">...</cfmail>
</cfif>

Notes

  • Depending on your version of cf, and whether you're using application.cfc or not, there are several ways to place a custom tag in an outside directory. There is also <cfmodule>
  • This is a sample only, something this basic is redundant, I was just trying to mimic what asker outlined. In this sample, I'm calling a query that could get all the data, only to use it to query row by row.
  • If you're not familiar with <cfqueryparam>, look it up, use it, love it.

Edit: While a CFHTTP method can serve this purpose, it suffers a few problems

  • Sessions are not automatically passed (even if the requesting server and destination server are the same.).
  • The page is accessed like a browser request. Application/OnRequestEnd are processed (and since session info is passed as well, this can cause problems trying to access files in secured areas.
  • Because of the above, the page would need to be in a folder with its own Application file to negate any application files above it in the directory hierarchy.
  • To combat 1, 2, and 3, You'd need to code in a layer of security, similar to your application's own security, so that the file is not vulnerable should the url be found.
  • Each call to the file via cfhttp would need to invoke some extra security checking.
  • It is significantly slower. In a very simple test with a zero-content application.cfc, the custom tag method was executing in literally <= 1/100th of the time. As actual function is added to the method, the difference in results would change.

Here is some sample code to test this yourself.

Contents of folder "safe":

Application.cfc

[ blank file, to negate my testing site's actual application.cfc ]

Testrun.cfm

<cfoutput><cfset starttick = GetTickCount()>
<cfloop from="1" to="20" index="i">
  <cfhttp url="http://mysamesite.com/safe/http.cfm?u=#i#" method="get" result="test">
  #test.filecontent#<br>
</cfloop>
CFHTTP Execution Time: #(GetTickCount() - starttick)#<br><br>

<cfset starttick = GetTickCount()>
<cfloop from="1" to="20" index="i">
  <cf_testtag u="#i#"><br>
</cfloop>
CustomTag Execution Time: #(GetTickCount() - starttick)#<br><br>
</cfoutput>

testtag.cfm

<cfoutput>The ID entered was #attributes.u#</cfoutput>

http.cfm

<cfoutput>The ID entered was #url.u#</cfoutput>

Results (in milliseconds) Each test was 20 passes at HTTP and 20 Passes at the custom tag.

CFHTTP  Tag
661ms   6ms
1624    5
616     5
460     4
522     6
816     4
Regular Jo
  • 5,190
  • 3
  • 25
  • 47
  • After implementing your solution, I'm getting an error: `Attribute validation error for tag cfmail. The value of the attribute query, which is currently rsHeadCoach, is invalid. The error occurred in D:\Inetpub\zzzz\admin\email\next-game-email-output.cfm: line 102 100 : 101 : – Joe Lowery Oct 13 '14 at 16:01
  • It sounds like rsHeadCoach is in the calling page, but not in the custom tag? If so, try changing your `` to ``. `caller scope` is how you can access variables from the calling page, while `Attributes` are attributes passed in the tag. – Regular Jo Oct 13 '14 at 16:09
  • 1
    @JoeLowery Bracketsage can't write it for you but he's giving you an approach that will work. Remember, every variable that's needed within the custom tag that is not already written or defaulted within the tag will need to be passed into the tag as attributes (like he's doing with the "ID") or accessed from the caller scope. So this approach will require some editing and rewrites on your part. – Mark A Kruger Oct 13 '14 at 16:20
2

You can do this by using cfhttp also

 <cfquery name="GetUIDs">
    select userid from users
 </cfquery>

 <cfloop query="GetUIDs">
   <cfhttp url="http://localhost:8500/cf10/test.cfm?id=#userid#" method="get" result="test">
</cfloop>
Keshav jha
  • 1,356
  • 8
  • 22
  • While this may meet your implementation, it's lazy. Each cfhtp is like a browser request. You would need/want to contain this in its own folder with it's own application.cfc and own authentication (perhaps mimicking your site's authentication) so that it's not freely exposed if someone should find it. And Finally, it's much slower. See http://pastebin.com/FWXcRmDB for the code required to do the test, as well as the results I got. – Regular Jo Oct 13 '14 at 19:04
  • There's a typo in that bin, the results for the tag route was never greater than 8ms. I seem to have lost a record in formatting it. – Regular Jo Oct 13 '14 at 19:17