Macros
Introduction
So far you have seen <MvEVAL> used to obtain (and display) the value of variables and expressions. Sometimes you will want to obtain and use a variable value in contexts where <MvEVAL> is not appropriate. For example, you cannot assign the value of a variable to an HTML attribute using <MvEVAL> or a Miva Script expression.
One way to use a variable value is by using it in a macro expression. This allows you to use the contents of a variable as in-line HTML or Miva Script code. The syntax of a macro is:
- &[ variable_name ];
When a Miva Script tag is processed, any variables found inside '&[ ...];' will be evaluated before the rest of the tag is parsed and or executed.
Note: A macro can contain only a single variable, and no expressions, literals, or functions.
For example, suppose the variable server_name has the value www.sq.com. The following code uses the value of server name to create a URL:
- <A HREF="http://&[server_name];/index.html">Home Page</A>
In this example, the value of server_name will be substituted for the '&[...];'. The tag above is equivalent to:
- <A HREF="http://www.sq.com/index.html">Home Page</A>
The characters '&' will also function as the start of a macro: &[var1]; and &[var1]; are equivalent. The semi-colon at the end of a macro is optional, but, if you want a semi-colon to be displayed after a macro, you will have to enter it twice (for example, &[var];;). To summarize, the following four forms are equivalent:
- &[variable];
- &[variable]
- &[variable];
- &[variable]
The variable used in a macro can also stand for executable code. The current implementation of Miva Script does not support macros that stand for Miva Script code that involves a loop or other jump.
Note: Both expressions and macros can be used to specify the values of Miva Script attributes. Only macros can be used to specify the values of HTML attributes.
This attribute assignment is correct:
- <FORM ACTION="&[documenturl];">
- <FORM ACTION="{documenturl}">
Macros provide the capability for "indirection" and self-generating code:
- <MvASSIGN NAME="var_a" VALUE="var_b">
- <MvASSIGN NAME="var_b" VALUE="burrito">
- <MvEVAL EXPR="{&[var_a];}">
'<MvEVAL EXPR="{&[var_a];}">' will display the value burrito. This may seem surprising at first, but you should consider the order in which the Miva Script code is evaluated. First, the macro substitution takes place: in this step, the expression '&[var_a];' is replaced by the current value of var_a. This is the string, not the variable, 'var_b'. The <MvEVAL...> tag becomes, in effect:
- <MvEVAL EXPR="{var_b}">
Then, the resulting <MvEVAL...> is executed. The EXPR '{var_b}' is evaluated, and its value, the string 'burrito', is displayed.
Many of the functions of macros can also be carried out using the string concatenation operator, '$'. For example:
<MvASSIGN name="firstname" value="Alex">
<MvASSIGN name="lastname" value="DeLarge">
<MvEVAL expr="&[lastname];, &[firstname];">
<MvEVAL expr="{lastname $ ', ' $ firstname"}>
The two <MvEVAL> tags in this example each display the same thing: 'DeLarge, Alex'.
Note: If the value of a variable contains double quotes, using it in a macro as the value of an attribute may cause a syntax error. The form:
- EXPR="{var}"
- EXPR="&[var];"
In general, you should not use a macro unless you have a very good idea of the format of the value in the variable it contains. See also the following section on security.
Security Issues with Macros
Because Miva Script macros can be used to insert executable Miva Script code directly into a script, a potential security problem exists. If user input is displayed using a macro, and that input contains executable Miva Script code (such as calls to built-in file manipulation functions) then unexpected and undesirable results may occur. However, good programming practices can prevent this from happening.
Note: A macro in a quoted string that is inside an expression is expanded inside of the quoted string and will not be executed.
All user input (for example, input from a FORM, from a data file, from the URL command line, or from a POST action) should be validated to ensure that it does not contain executable code. If it does, it must not be displayed using a macro (or if it is, it must be entity-encoded). Ideally, your script should issue an error message to the user indicating that tags must not be entered. Variations on the following code fragment will test whether the input contains any executable code (that is, tags). In this example, assume that input from a FORM is contained in the variables field1, field2, field3, field4, and field5.
- <MvASSIGN
- NAME="input"
- VALUE="{field1$field2$field3$field4$field5}">
- <MvIF EXPR="{('<' IN input) OR ('>' IN input)}">
- <P>Invalid input! Please do not enter HTML or Miva Script tags in any field!</P>
- </MvIF>
Entity-encoding a variable makes the contents of the variable safe and can be used instead of the code above.
Use <MvEVAL> instead of a macro to display the values of variables. Macros must be used if you want to insert a variable's value in an attribute, but for displaying text to the browser a macro can always be replaced by an <MvEVAL> tag. For example:
- <MvCOMMENT>Possibly unsafe!</MvCOMMENT>
- .
- .
- .
- You said: &[someinput];
- <MvCOMMENT>Safe!</MvCOMMENT>
- .
- .
- .
- You said: <MvEVAL EXPR="{someinput}">
If your program is not relying on the value of a variable being set via user input, and that variable is being displayed with a macro, the variable should be explicitly initialized (set to some initial value with <MvASSIGN>) in the program. This prevents values from other sources inadvertently or intentionally being output.
Macro Encoding
The value of a macro can be URL- or entity-encoded before it is put out. This can be used to make the macro output secure.
Entity-encoding
The following construction converts all characters in the macro output that have HTML entity equivalents to those entities (this is equivalent to applying the encodeentities() function):
- &[var:entities];
- <MvASSIGN NAME="Step1" VALUE="Press <Enter>">
- &[Step1];<BR>
- &[Step1:entities];
When &[Step1]; is evaluated, the string <Enter> is passed to the browser; since this is an unknown tag, it is not displayed. When &[Step1:entities]; is evaluated, the '<' and '>' characters are converted to entities: Press <Enter>. This string is displayed as intended in the browser.
URL-encoding
A string that results from a macro evaluation can be URL-encoded to make it safe to use as a name or value in a URL query string (that is, the part of a URL to the right of the '?', if there is one). In this encoding, special characters such as +, %, &, =, and space are replaced by safe equivalents. Note that encoding query strings is not identical to encoding the 'document' part of the URL (the part to the left of the '?'): for example, a space in a query string is encoded as '+', whereas in a document URL it is encoded as '%20'.
The following construction URL-encodes the macro output; this is equivalent to applying the encodeattribute() function.
For example, if var has the value 'R&D', &[var:attribute]; produces 'R%26D'.
You should use this form of the macro if you are using the macro output as a name or value in a query string. Do not encode an entire query string: if you do, the '=' between names and values, and the '&' between pairs will be encoded and thus lose their special meanings.