# eForm - The Electronic Form Snippet

## Who's responsible for eForm

Originally developed by Raymond Irving (15-Dec-2004)
Version 1.3 - 1.4 extended by: Jelle Jager (TobyL) September 2006

Captcha image support - thanks to Djamoer
Multi checkbox, radio, select support - thanks to Djamoer
Styles (for these docs) 'borrowed' from Adam Crownoble's QuickEdit

## What is eForm?

eForm converts a web form into an email which can be sent via email to specified users. Its main features are: html form mail with attachments, auto-respond, report generation using placeholders and extended form validation.

## What's New

### Version 1.4.4.1 - 1.4.4.8

- eForm now retains default values for check boxes and radio buttons
- text input fields now retain default value set in form template
- Added pixelchutes' phx workaround (use (()) instead of [++] in snippet call)
- Added proper ef_validation_message language string
- FS#960 - removed trimming of $param - values with leading or trailing spaces would always fail validation
- bugfix: &jScript parameter doesn't accept chunks, only a link to a JS file if more than one chunk is declared (eg &jScript=`chunk1,chunk2)
- bugfix: &protectSubmit creates hash for all fields instead of fields declared in &protectSubmit
- bugfix: Auto respond email didn't honour the &sendAsText parameter
- bugfix: The #FUNCTION validation rule for select boxes never calls the function
- bugfix: Validation css class isn't being added to labels.
- Work around for setting required class on check & radio labels
- bugfix: If eform attibute is set on multiple check boxes only the last value is set in values list
- Security fix: Additional sanitization applied after stripslashes is used on fields
- Security fix: Send sendirect, ccsender and autotext mails only to the first mail address of the comma separated list.
- Added: Multiple event functions separated by comma.

You can see a more extensive version history here.

## Installation

- Unzip the zip file into the assets/snippet/ folder. You should now have an extra folder called eform.
- Create a new snippet, name it eForm and copy and paste the content of the eform.snippet.tpl file
- Start reading this file and the examples
- Create forms

## Snippet Parameters

eForm is very flexible and there's quite a collection of parameters you can use to get eForm to do what you want. Read some of the examples if you're unsure what to do.

#### Required parameters

- &formid
  This is a unique id used to identity a form during postbacks. This is useful in cases where more than one form exists on a page. Your form template should either have a hidden field with the same formid `<input type="hidden" name="formid" value="formName" />` or (from eForm 1.4.x) you can set the the id in the form tag itself: `<form id="formName"...>`;
- &tpl
  chunk name (non-numeric) or document id (numeric) to use as a form template (new in 1.4.4) You can now also use a snippet as the template source. No parameters are forwarded to the snippet call in this version. For the regular form fields you do not normally need to add placeholders, they automatically get inserted by eForm. The esception to this rule are in the case of event functions where you want to set specific values. Special placeholders available are: [+validationmessage+], [+postdate+],[+verimageurl+] & [+debugText+]. You should have the [+validatiomessage+] placeholder in all your forms. The others you may need depending on other parameters.
- &report
  chunk name (non-numeric) or document id (numeric) to use when generating reports. Tags: Same as for `&tpl`plus [+fieldname+], where fieldname stands for the name of each form field you wish to include.

#### Optional parameters

- &to (Optional)
  Email address to send eForm information to For multiple recipients separate emails with a comma (,) If omitted the site settings email address will be used
- &from (Optional)
  Sets the email address to appear in the From section of the email
- &fromname (Optional)
  Sets the name of the sender in the From section of the email
- &replyto (Optional)
  Email address or fieldname containing email address Sets the email address to appear in the ReplyTo section of the email
- &sendirect (Optional)
  This will use the form field called email to supply the email address to send the message to. Set to 1 to activate send direct. Defaults to 0
- &cc (Optional)
  Same as `&email`but for Cc:
- &bcc (Optional)
  Same as `&email`but for Bcc:
- &ccsender (Optional)
  Set to 1 to send the user a copy of the submitted form. Defaults to 0 eForm will look for the user's email address inside a field called email.
- &subject (Optional)
  Subject to appear in email Can include ((form fields)). E.g. Purcase Order for ((firstname)) ((lastname))
- &noemail (Optional)
  Prevents eform from sending emails e.g. no-reply@mydomain.com Set to 1 to disable emails. Defaults to 0
- &mailselector (Optional)
  Sets the name of the form field to use as a selector to select a single email from the comma (,) delimited emails assigned the `&to`parameter. This selector field will act like a numeric index to select an email. It will start at 1 for the first email and ends at N for the last email in the list.
  For example: `&to =`sales@me.com,support@me.com,billing@me.com` `&mailselector`=`topic``
  On the web form the topic fields is actually a dropdown menu. when the user selects a topic from the list the value 1,2 or 3 will be sent to eForm which will then be used to select one of the three emails assigned to the `&to`parameter. This email address will be the address used to send the email to.
- &mobile (Optional)
  Mobile email address. This email is used to send a short notification message to a mobile device.
- &mobiletext (Optional)
  Text message to send to mobile device Can include ((form fields)). E.g. Order for `((firstname))`
- &thankyou (Optional)
  chunk name (non-numeric) or document id (numeric) to use as a thank you message displayed to the user after a successful submit. Tags: same as for `&tpl`
- &gotoid (Optional)
  document id to load after sending message. See also `&thankyou`
- &category (Optional)
  Category ID or name used to categorize eForms. If category is not found a new category will be created. This will appear in the subject of the email sent to the user
- &keywords (Optional)
  Comma delimited keywords or [+formfields+] used when searching databank E.g. [+firstname+], [+lastname+], [+email+]
- &autosender (Optional)
  email to display as sender of the auto-respond message e.g. no-reply@mydomain.com
- "autoSenderName (new in 1.4.4) (optional)
  Name to display as sender of the auto-respond message.
- &automessage (Optional)
  chunk name (non-numeric) or document id (numeric) to use as an auto-responder message Can include [+form fields+]. E.g. [+firstname+] - tags: [form_fields],[postdate] - note: eForm will send the auto-respond message to the email address specified inside the [email] form field.
- &allowhtml (Optional)
  Set to 1 to allow user to enter html tags. Defaults to 0
- &language (Optional)
  Support for multilingual validation and error messages. Uses same language names as MODx.
- &vericode (Optional)
  Enables verification code. The template contain a vericode field and a [+vericode+] placeholder
- &debug (Optional)
  Set to 1 for extended error messages in form validation. Mostly for debugging #LIST and #SELECT validation.
- &sendAsHtml (optional)
  Force email messages to be in Html. Possible values: &sendAsHTML=`1`- send all messages as html, &sendAsHTML=`report,autotext,mobile`- send specified messages as html
- &sendAsText (optional)
  Force email message to be in plain text. Possible values: &sendAsText=`1`- send all messages as text only, &sendAsText=`report,autotext,mobile`- send specified messages as text only
- &sessionVars (optional)
  Comma delimited list of $_SESSION variable names. These will be added to the list of field values before the form is displayed and can for instance be used to populate (hidden) fields. When using this parameter make sure you are not disclosing sensitive information from the session!! (a hidden field is not all that hidden afterall)
  As eForm does not parse the complete form 1st time around you will have to have the same placeholders in the form template so the form can receive the values. So for example: `[!eForm &sessionVars=`jobID` ... !]`and `<input type="hidden" value="[+jobID+]" />`
- &postOverides (optional)
  Used in combination of `&sessionVars`. Normally session variables will overide posted values. By setting &postOverides=`1` posted values will take precedence.
- &reportAbuse (optional)
  Setting &reportAbuse=`1` will send an email to the system specified email address if email injection attempts are noticed by eForm. (Use sparingly...)
- &cssStyle (optional)
  Adds a style declaration to the <head> section of the page when either the form is displayed or the thank you page is displayed (only if the `&thankyou` parameter is set). Values can be a document id (numeric), chunk name or (relative or absolute) url to css file. Multiple values can be separated by a comma (in fact all three values can be mixed).
  examples:
  `[!eForm &cssStyle=`assets/site/forms.css,chunkName` ... !]`
  `[!eForm &cssStyle=`chunkName` ... !]`
  `[!eForm &cssStyle=`http://mysite.com/assets/styles/forms.css` ... !]`
  Chunks (and documents if a doc id is given) can return a values in the form of:
  1. an inline style block, eg. `<style type="text/css">/*some styles*/</style>`
  2. a link to stylesheet(s), eg. `<link href="assets/site/forms.css" rel="stylesheet" type="text/css">`
  3. a comma separated list of urls, eg. `assets/site/forms.css,assets/site/more.css,assets/site/gone_overboard.css`
- &jScript (optional)
  Similar to `&cssStyle` but for adding javascript to the <head> of the page document. Currently Javascript is only added when the form is displayed.
- &protectSubmit(optional) defaults to 1 (on)
  Protects against submitting a form multiple times with the same data. Submitting the form becomes disabled after the first successful submit while the value from key form fields remains the same. This is achieved by setting (and comparing) a session variable with an md5 hash from these key fields. Which fields are compared depends on the value of `&protectSubmit`.Possible values are 0 (off), 1 (all 'required' fields are used) or you can set a comma separated list of field names. To ensure that the session variable works separatedly for different forms the session variable name is based on `&formid` ({formid}_hash).
- &submitLimit (optional) off (0) by default
  Enforces a time limit (in minutes) between form submits. After the form has been submitted successfully it can not be submitted again for `&submitLimit` minutes irrespective of the form data. When used in combination with `&protectSubmit` `submitLimit` takes precedence, meaning that when the time limit has expired the form can be submitted again regardless of the setting of `&protectSubmit` (it will unset the session variable). As with `&protectSubmit` this parameter uses a session variable with a variable name based on &formid.
- &requiredClass (optional)
  Css class name. Will add class in (empty) required form fields on validation. Existing classes will be preserved.
  If you have already set a class for a field or label and you get unexpected css results check the order in which you have declared the classes. The `&requiredClass` is added to the beginning of any classes already set.
- &invalidClass (optional)
  Css class name. Will add class in invalid form fields on validation. Existing classes will be preserved.
- &runSnippet (new in 1.4.4) (optional)
  Expects a snippet name. Snippet will be run before any eForm handling. One parameter, the &&formid will be passed to the snippet. Any return value from the snippet is discarded. This can be used to insert functions as an alternative to declaring a separate snippet in the document. Sadly eForm will silently ignore a snippet that does not exist due to the way $modx->runSnippet handles snippet return values.
- &snipFolder (new in 1.4.4) (optional)
  For those that want to keep different versions of eForm active. You can now save all of eForm's files in a different directory and set the &snipFolder accordingly. You can for instance save version 1.4.4 in the 'assets/snippets/eform/1.4.4' folder and set `&snipFolder=`eform/1.4.4``. The value of &snipFolder is added to the basic snippets folder 'assets/snippets/'.It should not include a closing slash (/)!

#### PHP Event Functions:

The eForm event functions are now incorporated into the parameters. They are:

- &eFormOnBeforeMailSent (optional)
  Expects a list of comma separated function names. These functions will be called after the form has been validated and before the report and thankyou templates have been parsed and any emails have been sent out. See this example on how to use the events.
  - &$fields - (as reference) an associative array of field and placeholder values.
- &eFormOnMailSent (optional)
  Expects a list of comma separated function names. These functions are called after all templates have been parsed and any emails were sent.
  - &$fields - (as reference) an associative array of field and placeholder values.
- &eformOnBeforeFormParse (optional)
  Expects a list of comma separated function names. These functions are called after the templates are loaded and the formid is found valid. The function should accomodate the following parameter:
  - &$fields - (as reference) an associative array of field and placeholder values.
  - &$templates - (as reference) an associative array of loaded templates with indexes 'tpl', 'report','thankyou' & 'autotext'. Be aware that the latter three will only have a value if the form has been posted!
- &eFormOnBeforeFormMerge (optional)
  Expects a list of comma separated function names. These functions will only be called whenever the form is displayed and just before all placeholders are merged. The function should accomodate the following parameter:
  - &$fields - (as reference) an associative array of field and placeholder values.
- &eFormOnValidate (optional)
  Expects a function name. This function will be called directly after the form validation has taken place. You can use this event to add your own extra validation logic. The function should accomodate the following parameters
  - &$fields - (as reference) an associative array of field and placeholder values.
  - &$vMsg - (as reference) a numeric array of validation error messages.
  - &$rMsg - (as Reference) a numeric array of missing required fields.
  - &$rClass - (as Reference) an associative array of fieldnames and classes assigned.

### Examples:

`[!eForm? &to=`me@mydomain.com` &gotoid=`1` &tpl=`orders` &report=`orderreport` !]`
`[!eForm? &to=`sales@mysuppliers.com` &category=`Purchase Order` &tpl=`chunkPurchaseOrder` &report=`chunkPurchaseReport` !]`

## Placeholders

For all normal form fields eForm automatically inserts appropriate placeholders. However there are a few that you may need to add manually:

- `[+validationmessage+]` - This should be somewhere in your form template or document. It is used for any validation error messages. From 1.4.2 the way the placehloder is entered has changed. Firstly you no longer need to place it in the form template. You can now place it anywhere in your document (or even in the global page template). Secondly you don't need to place any hml tags around the placeholder (in fact you probably should not). Any html markup is now included in the `$_lang['ef_validation_message']` variable in the eform language files (which you can change as required).
- `[+vericode+]` & `[+verimageurl+]` - These are needed in the form if you want to use the CAPTHCA code. See the Examples on how to use these.
- `[+postdate+]` - This placeholder can be used in reports and in the thankyou template and will be filled with the current date and time (date on the server that is)
- `[+debug+]` - From version 1.4.1 this is automatically placed (if debug is on) in the form and thankyou template. It is not automatically placed in the report template! This is to avoid any server side information to accidentally be sent out via email. If you need debug info in test emails you will have to add this placeholder in the report template yourself.

## Datatypes and formatting

eForm is incorporating a form parser which extracts formatting and validation options from each form field. To set options for a field add the `eform` (pseudo) attribute to each required form field.

`<input type="text" name="color" eform="A Color:string:1" />`

The basic format of the eform attribute is:
`[description/title]:[datatype]:[required]:[validation message]:[validation rule]`

### Data types

You only need to set the following data types. Others will be set automatically (radio & checkbox as they are, string for textbox and listbox for select)

Standard validation: All fields that are required will be checked if they are left empty.

- string - No specific validation besides checking if it's empty if the field is required.
- date - Checks if it is a valid date (based on php's strtotime() function)
- integer - Checks if it is a number (does not check if it is in fact an integer)
- float - Checks if it is a number
- email - Checks if it's a valid email address using a simple regular expression
- file - (for file upload input) - checks if a size error occurs, does not currently check file type
- html - Same as string except that it converts line endings (\n) to <br /> tags

The listbox, checkbox and radio fields do normally not require the datatype to be set. eForm will recognize these automatically. It will validate the values against the list of values placed in the form.

## Extended Server Validation

This version instroduces extended server validation and word filtering using very flexible validation rules that can be set in the `eform` attribute. You can set 2 extra validation parameters, a custom error message and a validation or filter rule.

example: `eform="Year of Birth:integer:1:Must be between 1950 and 2002:#RANGE 1950-2002"`

### The validation rules

- #LIST - comma separated list of valid values
  example: `#LIST blue,red,green.maroon`
- #RANGE - a comma separated list of numbers or numeric ranges. When setting a range the order is not important. 1~10 or 10~1 will both validate a number between 1 and 10 (inclusive). Handles negative as well as positive numbers
  example: `#RANGE 1,3,-5~-15,60~82`
- #SELECT - list of valid values retrieved from a database query The query should only return a single column of values (the function only checks against the first returned column). You can use the `{DBASE}` `{PREFIX}`tags which will be replaced by the MODx database name and table prefix respectively.
  example: `#SELECT keyword FROM {PREFIX}site_keywords`
- #EVAL - string of php code. Should return either true or false
  deprecatedAlthough #EVAL still works in eForm 1.4 this rule will very likely no longer be supported in future versions. Use #FUNCTION instead.
- #FUNCTION - Name of a function. The function should expect one parameter (the posted value) and return either TRUE or FALSE. See the eform event example on how you can include a function. example: `#FUNCTION myValidationFunction`
- #REGEX - regular expression - syntax as for preg_match() - see php manual
  example: `#REGEX /^[a-z]+ [a-z0-9_]+/i`
- #FILTER - Filters do not validate the input but simply replace words or values using filter criteria. You can use the following filters:
  - #FILTER #LIST
    use double pipe to separate 2 comma separated lists of words and replacement values.
    example; `#FILTER #LIST badword,verybadword||goodword,verygoodword`
  - #FILTER #EVAL
    example: `#FILTER #EVAL return myFilterFunction($value);`
    (offcourse you have to make sure the function exists somehow)
    example filter function
    `function myFilterFunction($value){
    $badWords = array('scribble','coding');
    $goodWords = array('design','sleep');
    return str_replace($badWords,$goodWords,$value);
    }`
  - #FILTER #REGEX
    regular expression replace - syntax as for preg_replace() separate the search and replacement expression with a double pipe symbol (||)
    TODO: example

### Select boxes, radio options and checkbox fields

Select boxes, radio options and checkbox fields now have working automatic validation. Any input for these fields is validated against the values set in your form template. This avoids anyone tampering with the form by adding their own values to these fields

### Hidden fields

By default hidden fields are validated as a protection against tampering by comparing the input against the value set in the form template (much like the select, checkbox and radio fields) In some circumstances this may not be desirable however. For instance when you use some javascript in your form to store a result in a hidden field. In those cases you can turn this behaviour off by setting the eform attribute (with or without it's own validation).

Hidden field example 1.
The default behaviour is handy for instance if you are storing a document id and want to be sure no one can tamper with the id. the field would look like this:
`<input type="hidden" name="docId" value="31" />`

Hidden field example 2.
Suppose you have a form where a javascript calculated value is stored in a hidden field. To avoid the hidden field being validated at all you add the following eform attribute: `<input type="hidden" name="calculatedField" value="" eform="::0::" />`

Hidden field example 3.
Same scenario as 2 but suppose you want to make sure a value is returned and that it stays within a certain range. The eform attribute is set with: title,integer data type, required field, error message and validation with #RANGE (in this example a value between 1-10) `<input type="hidden" name="calculatedField" value="" eform="Calculated Value:integer:1:Calculation out of range:#RANGE 1-10" />`

### Form field examples with validation

1. Selectbox - set as required field (no validation required)

<select name="mySelect" eform_options="Select Country::1" /> (datatype left blank)
<option value="en-au">Australia</option>
<option value="en-us">USA</option>
</select>

2. Textbox - required and format set to date

<input type="text" name="dobDate" eform_options="Date of Birth:date:1:@EVAL return (strtotime($value)!==-1)?true:false;" />

3. Multiple checkbox - required, eform_options only set once.

<input type="checkbox" name="myColors[]" value="Red" eform_options="Colors::1" /> (datatype left blank)
<input type="checkbox" name="myColors[]" value="Green" /> (datatype left blank)

## Todo

- Custom css classes for invalid fields (add to or create class attributes)