Earlier today on Twitter @samhamilton and I shared a few messages about finding a replacement for cfdump. Apparently, some ColdFusion hosts lock down access to internal Java components which unfortunately breaks cfdump. He linked to this forum posting as an example. I wasn't able to replicate that on my ColdFusion 901 server so it may be an issue with 8 only. Either way I thought it would be fun to see if I could recreate cfdump quickly. I wrote the following tag in about 20 minutes (10 minutes for the initial version, then about 10 more minutes later on for small changes). It works best with arrays, structs, and queries, but will try to display a component as well. It also sniffs for JSON strings and will automatically deserialize them. The layout is - of course - not optimal. But it gets the job done. Here is a sample screen shot:
I've attached a zip of the custom tag to the bottom of this entry. But for those who just want to see the code, I've pasted it below. Basically it just does a few type checks and iterates through the data, recursively calling itself where it makes sense. Definitely not rocket science but maybe it will be useful. Of course, normally you don't want to ever use cfdump in production. But I've often used it for error emails and other logging/reporting needs.
Edit on October 7: I added basic XML support.
<cfparam name="attributes.var">
<cfparam name="attributes.top" default="">
<cfif len(attributes.top) and not isNumeric(attributes.top)>
<cfset attributes.top = "">
<cfelseif isNumeric(attributes.top) and (attributes.top lte 0 or round(attributes.top) neq attributes.top)>
<cfset attributes.top = "">
</cfif>
<cfif not structKeyExists(request, "_cffakedump")>
<cfoutput>
<style>
table, th, td {
border: 1px solid black;
}
td {
padding: 5px;
}
th, .key {
background-color: ##e3e392;
}
</style>
</cfoutput>
<cfset request["_cffakedump"] = 0>
<cfelse>
<!--- quick sanity check for pointers --->
<cfset request["_cffakedump"]++>
<cfif request["_cffakedump"] gt 1000>
<cfabort/>
</cfif>
</cfif>
<cfif isSimpleValue(attributes.var)>
<cfif attributes.var is "">
<cfoutput>[empty string]</cfoutput>
<cfelseif isJSON(attributes.var)>
<cfset newVar = deserializeJSON(attributes.var)>
<cfoutput><table><tr><th>JSON</th></tr><tr><td></cfoutput>
<cf_fakedump var="#newVar#" top="#attributes.top#">
<cfoutput></td></tr></table></cfoutput>
<cfelse>
<cfoutput>#attributes.var#</cfoutput>
</cfif>
<cfelseif isArray(attributes.var)>
<cfoutput>
<table>
<tr>
<th colspan="2">array (#arraylen(attributes.var)# items)</th>
</tr>
<cfif not len(attributes.top)>
<cfset attributes.top = arrayLen(attributes.var)>
</cfif>
<cfloop index="x" from="1" to="#min(arrayLen(attributes.var), attributes.top)#">
<tr valign="top">
<td class="key">#x#</td>
<td>
<cfif isSimpleValue(attributes.var[x])>
#attributes.var[x]#
<cfelse>
<cf_fakedump var="#attributes.var[x]#" top="#attributes.top#">
</cfif>
</td>
</tr>
</cfloop>
</table>
</cfoutput>
<cfelseif isObject(attributes.var)>
<cfset data = getMetadata(attributes.var)>
<cfoutput><table><tr><th>Component: #data.fullname#</th></tr><tr><td></cfoutput>
<cf_fakedump var="#data#">
<cfoutput></td></tr></table></cfoutput>
<cfelseif isStruct(attributes.var)>
<cfoutput>
<table>
<tr>
<th colspan="2">struct</th>
</tr>
<cfloop item="key" collection="#attributes.var#">
<tr valign="top">
<td class="key">#key#</td>
<td>
<cfif isSimpleValue(attributes.var[key])>
#attributes.var[key]#
<cfelse>
<cf_fakedump var="#attributes.var[key]#" top="#attributes.top#">
</cfif>
</td>
</tr>
</cfloop>
</table>
</cfoutput>
<cfelseif isQuery(attributes.var)>
<cfset cols = attributes.var.columnlist>
<cfif not len(attributes.top)>
<cfset attributes.top = attributes.var.recordCount>
</cfif>
<cfoutput>
<table>
<tr>
<th colspan="#listLen(cols)+1#">query (#attributes.var.recordcount# rows)</th>
</tr>
<tr>
<td> </td>
<cfloop index="c" list="#cols#">
<th>#c#</th>
</cfloop>
</tr>
<cfloop query="attributes.var" endrow="#min(attributes.var.recordCount,attributes.top)#">
<tr>
<td class="key">#currentRow#</td>
<cfloop index="c" list="#cols#">
<td>
<!--- could be complex --->
<cfset theVal = attributes.var[c][currentRow]>
<cfif isSimpleValue(theVal)>
#theVal#
<cfelse>
<cf_fakedump var="#theVal#" top="#attributes.top#">
</cfif>
</td>
</cfloop>
</tr>
</cfloop>
</table>
</cfoutput>
<cfelseif isXMLDoc(attributes.var) or isXMLNode(attributes.var)>
<cfoutput>
<table>
<tr>
<th colspan="2"><cfif isXMLDoc(attributes.var)>xml<cfelseif isXmLNode(attributes.var)>xml element</cfif></th>
</tr>
<cfif isXMLDoc(attributes.var)>
<cfset child = attributes.var.xmlRoot>
<tr>
<td>#child.xmlName#</td>
<td><cf_fakedump var="#child#"></td>
</tr>
<cfelseif isXMLNode(attributes.var)>
<tr>
<td>xmlText</td>
<td>#attributes.var.xmlText#</td>
</tr>
<cfset kids = attributes.var.xmlChildren>
<cfloop index="x" from="1" to="#arrayLen(kids)#">
<tr>
<td>#kids[x].xmlname#</td>
<td><cf_fakedump var="#kids[x]#"></td>
</tr>
</cfloop>
</cfif>
</table>
</cfoutput>
<cfelse>
<cfoutput>[FakeDump] Sorry, I couldn't handle this data.</cfoutput>
</cfif>