The Scopes lesson introduced url as a built-in scope holding query-string parameters. The Form Validation lesson's isValid() and cfparam apply directly here too, url values are exactly as untrusted as anything submitted through a form, they just arrived a different way.
Learning Objectives
After completing this lesson, you'll be able to:
- Read and default a URL parameter with cfparam.
- Validate a URL parameter's type or format with isValid() before using it.
- Safely build a link with a dynamic parameter using URLEncodedFormat.
- Recognize Lucee's dotted-notation URL parsing behavior.
How a URL Parameter Reaches Your Code
?userId=42&mode=edit on the Request
url Scope
cfparam Default / isValid() Check
Safe to Use
Reading a Basic URL Parameter
<cfset currentTarget = url.userId> <cfdump var="#url#">
currentTarget = url.userId; writeDump(url);
A Real Example: Defaulting Optional URL Parameters
<cfparam name="url.page" type="numeric" default="1">
<cfparam name="url.sort" type="string" default="name">
<cfquery name="products" datasource="myDsn">
SELECT * FROM products
ORDER BY #url.sort#
</cfquery>cfparam only sets the default if url.page or url.sort don't already exist, exactly the case when a user visits the page without those parameters at all.
A Real Example: Validating a URL Parameter Before Using It
<cfif not isValid("integer", url.id)>
<cfthrow type="application" message="Invalid product id.">
</cfif>
<cfquery name="product" datasource="myDsn">
SELECT * FROM products WHERE id = <cfqueryparam value="#url.id#" cfsqltype="cf_sql_integer">
</cfquery>cfqueryparam already protects the query itself, but validating url.id's type first avoids sending obviously invalid data into a database lookup at all, and gives a clear error instead of a confusing downstream failure.
Building a Link With a Dynamic Parameter Safely
<cfset searchTerm = "coffee & tea"> <a href="/search.cfm?q=<cfoutput>#URLEncodedFormat(searchTerm)#</cfoutput>">Search</a>
URLEncodedFormat replaces spaces with %20 and escapes non-alphanumeric characters so the value can't break the URL's structure. Adobe's own documentation now recommends EncodeForURL over URLEncodedFormat for new applications.
A Real Lucee-Specific Behavior: Dotted-Notation URL Parsing
On Lucee, a dotted URL parameter name is automatically parsed into a nested structure in addition to the flat key. Calling index.cfm?p=hello&p.ico=1 results in a url scope containing both url.p (a struct: {ico: "1"}) and the flat url["p.ico"] ("1") at the same time.
component {
this.formUrlAsStruct = false;
}Since Lucee 6.1, this.formUrlAsStruct=false disables the nested-struct parsing, leaving only the flat keys. Adobe ColdFusion doesn't do this at all, a dotted parameter name just stays a flat key there.
Common Beginner Mistakes
Trusting a URL parameter without validating it
It's exactly as untrusted as a submitted form field, anyone can type or change a query string directly in the address bar. Validate it the same way, with isValid() or cfparam's type checking.
Not defaulting an optional URL parameter before reading it
Reading url.page directly when it might not be present throws an error. cfparam with a default handles the case where the parameter is simply absent.
Concatenating a raw value into a link instead of encoding it
An unencoded value containing an & or a space can break the URL's structure or silently truncate. URLEncodedFormat (or EncodeForURL) exists specifically to prevent this.
Assuming Lucee's dotted-notation struct parsing also happens on Adobe ColdFusion
It doesn't, that behavior is Lucee-specific. On Adobe ColdFusion, a dotted parameter name like p.ico stays a flat key, url["p.ico"], with no nested struct produced.
Best Practices
- cfparam every optional URL parameter with a sensible default before reading it.
- Validate any URL parameter that feeds into a query or real business logic with isValid(), the same as a form field.
- Always encode a dynamic value with URLEncodedFormat (or EncodeForURL) before embedding it in a link.
- Don't rely on Lucee's dotted-notation struct parsing in code that also needs to run on Adobe ColdFusion.
Interview Questions
Why should a URL parameter be validated the same way as a form field?
It's just as untrusted, anyone can type or modify a query string directly. The same isValid()/cfparam techniques from form validation apply here too.
What does cfparam's default attribute actually do for a URL parameter?
It sets the value only if the parameter doesn't already exist, handling the case where a user visits the page without that parameter in the query string at all.
What does URLEncodedFormat protect against?
It escapes characters (spaces, &, and other non-alphanumeric characters) that would otherwise break a URL's structure when a dynamic value is embedded in a link.
What does Lucee do differently with a dotted URL parameter name like p.ico, compared to Adobe ColdFusion?
Lucee parses it into both a nested struct (url.p = {ico: "1"}) and the flat key, at the same time. Adobe ColdFusion just keeps the flat key, with no struct produced.
Summary
In this lesson, you read and defaulted URL parameters with cfparam, validated one with isValid() before using it in a query, safely encoded a dynamic value into a link with URLEncodedFormat, and covered Lucee's dotted-notation URL parsing, a real behavior that doesn't exist on Adobe ColdFusion.
What's Next?
The next lesson covers file downloads: serving a file to the browser as an attachment instead of rendering it inline.