.. index::
   single: Run-time substitution

.. _runsub:

*****************************************************************************
 Run-time Substitution
*****************************************************************************

:Author:        Steve Lime
:Contact:       steve.lime at DNR.STATE.MN.US
:Last Updated: 2017-04-30

.. contents:: Table of Contents
    :depth: 2
    :backlinks: top


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 :ref:`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:

.. code-block:: mapfile

    LAYER 
        NAME 'covertypes' 
        ... 
        VALIDATION
            "ctype" "[a-z]+"
        END
        CLASSITEM 'type' 
        CLASS # highlighted presentation 
            EXPRESSION '%ctype%' 
            ... 
        END 
        CLASS # default presentation 
            ... 
        END
    END

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. 

.. index::
   pair: Run-time substitution; Supported parameters


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
:ref:`cgi_mapfile_change_parameters`.
Below is a list of properties that do allow run-time substitution:

* CLASS: EXPRESSION

* CLASS: TEXT

* LAYER: CONNECTION

* LAYER: DATA

* LAYER: FILTER

* LAYER: TILEINDEX 

* LAYER: METADATA

  .. versionadded:: 7.0

* LAYER: PROCESSING

  .. versionadded:: 7.0

* OUTPUTFORMAT: FORMATOPTION: FILENAME (must have a `MAP` `VALIDATION`
  pattern)

  .. versionadded:: 6.2

* OUTPUTFORMAT: all FORMATOPTIONs

  .. versionadded:: 7.0

* MAP->WEB: METADATA (values only, not keys)

  .. versionadded:: 7.0

.. index::
   pair: Run-time substitution; FILTER

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 :ref:`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:

.. code-block:: mapfile

    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.

.. index::
   pair: Run-time substitution; Default value

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 :ref:`CLASS`, :ref:`LAYER` or
:ref:`WEB` validation blocks:

.. code-block:: mapfile

    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.

.. index::
   pair: Run-time substitution; VALIDATION

.. index::
   single: VALIDATION

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 :ref:`VALIDATION`
block in the `LAYER` definition. This is only slightly different from
the older `METADATA` mechanism.  :ref:`VALIDATION` blocks can be used
with :ref:`CLASS`, :ref:`LAYER` and :ref:`WEB`.

.. code-block:: mapfile

    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.
