Run-time Substitution¶
- Author
Steve Lime
- Contact
sdlime at gmail.com
- Last Updated
2021-05-14
Table of Contents
Introduction¶
Run-time substitution for the MapServer CGI has been around since version 4.0 and it’s use has continued to expand. In short, it allows you to alter portions of a mapfile based on data passed via a CGI request.
Warning
This functionality is only available via the mapserv CGI application. Within MapScript this is easy to do by yourself since the developer has complete control over how input is handled.
Case sensitivity¶
Since version 6.4, CGI parameter names are not case sensitive. CGI parameter values are case sensitive.
Basic Example¶
Let’s say you’d like the user to dynamically set a portion of an expression so they could highlight a certain land cover class, and you have a form element (called ctype) that allows them to choose between: forest, water, wetland and developed.
A request should look like (assuming “marsh” is a valid land cover class):
http://...mapserv?map=....&ctype=marsh
You could then set up a layer like so:
LAYER
NAME 'covertypes'
...
VALIDATION
"ctype" "^[a-z]{5,10}$"
END
CLASSITEM 'type'
CLASS # highlighted presentation
EXPRESSION '%ctype%'
...
END
CLASS # default presentation
...
END
END
Values for the ctype parameter are limited to lower-case characters a to z and the value can be from 5 to 10 characters long. The regex start (^) and end ($) anchors are important in limiting values - always use them.
When a request is processed, the value for ctype is substituted for the string %ctype% and the mapfile is processed as normal. If no ctype is passed in, the EXPRESSION will never be true so it doesn’t really hurt anything except for a slight performance hit. Often you would set a default class to draw features that don’t match, but that is not required.
Parameters Supported¶
Not every mapfile parameter supports run-time substitution and care has been taken to try and support those that make the most sense. All parameters must be validated. Remember, you also can do run-time configuration using the map_object_property type syntax detailed in Changing map file parameters via a form or a URL. Below is a list of properties that do allow run-time substitution:
CLASS: EXPRESSION
CLASS: TEXT
CLASS: TITLE
LAYER: CONNECTION
LAYER: DATA
LAYER: FILTER
LAYER: TILEINDEX
New in version 7.0.
LAYER: METADATA
New in version 7.0.
LAYER: PROCESSING
New in version 6.2.
OUTPUTFORMAT: FORMATOPTION: FILENAME (must have a MAP VALIDATION pattern)
New in version 7.0.
OUTPUTFORMAT: all FORMATOPTIONs
New in version 7.0.
MAP->WEB: METADATA (values only, not keys)
FILTERs¶
You can use runtime substitutions to change values within a FILTER as you go. For example your FILTER could be written like so:
FILTER (multimedia='%multimedia%' and seats >= '%nseats%' and Sound= '%sound%')
Then (assuming you’re using the CGI interface) you could pass in variables named multimedia, nseats and sound with values defined by the user in an HTML form.
You should also define VALIDATION expressions on these variables to guard against unintentional SQL being submitted to postgis (since version 6.0, validation is mandatory). Within the layer you’d do the following:
VALIDATION
'multimedia' '^yes|no$'
'sound' '^yes|no$'
'nseats' '^[0-9]{1,2}$'
END
The validation strings are regular expressions that are applied against the appropriate variable value before being added to the FILTER. The first two limit the value of multimedia and sound to yes or no. The third limits the value for nseats to a 2 digit integer.
Default values if not provided in the URL¶
The runtime substitution mechanism will usually create syntactically incorrect, and almost always semantically incorrect mapfiles if the substitution parameter was not provided in the calling URL.
Since version 5.6, you can provide a default value for any substitution parameter, that will be applied if the parameter was not found in the url. You do this by providing special entries inside CLASS, LAYER or WEB validation blocks:
VALIDATION
'default_sound' 'yes'
'default_nseats' '5'
'default_multimedia' 'yes'
END
In this example, the mapfile will be created as if the url contained “&sound=yes&nseats=5&multimedia=yes”.
Providing a default value for a substitution parameter in the WEB section of the MAP wasn’t implemented until version 7.0.7.
If identical default keys appear in more than one validation block then keys in more specialised blocks override those in more generalised blocks. i.e. CLASS overrides LAYER which overrides WEB. The same functionality is available using METADATA blocks instead of VALIDATION but this is deprecated as of MapServer 5.4.0. This behavior is also accessible in the shp2img utility, allowing you to test runtime substitution mapfiles without using a webserver.
VALIDATION¶
Because runtime substitution affects potentially sensitive areas of your mapfile, such as database columns and filenames, it is mandatory that you use pattern validation (since version 6.0)
Pattern validation uses regular expressions, which are strings that describe how to compare strings to patterns. The exact functionality of your systems’ regular expressions may vary, but you can find a lot of general information by a Google search for “regular expression tutorial”.
As of MapServer 5.4.0 the preferred mechanism is a VALIDATION block in the LAYER definition. This is only slightly different from the older METADATA mechanism. VALIDATION blocks can be used with CLASS, LAYER and WEB.
VALIDATION
# %firstname% substitutions can only have letters and hyphens
'firstname' '^[a-zA-Z\-]+$'
# %parcelid% must be numeric and between 5 and 8 characters
'parcelid' '^[0-9]{5,8}$'
# %taxid% must be two capital letters and six digits
'taxid' '^[A-Z]{2}[0-9]{6}$'
END
If identical keys appear in more than one validation block then keys in more specialised blocks override those in more generalised blocks. i.e. CLASS overrides LAYER which overrides WEB.
Magic values¶
Some runtime substitutions have special caveats.
- ID
In addition to any defined METADATA or VALIDATION, the ‘id’ parameter will be subjected to a special check. It must be alphanumeric and cannot be longer than 63 characters.