Extension:FormHandler send form by Email

FormHandler send form by Email extension allows to create forms on wiki pages in a safe way. The contents can be sent by email. It sends all fields and the user IP and - if the user is logged in - his/her username. This extension is suitable for creating simple forms. If you need very sophisticated things, you are probably better off not doing it inside MediaWiki anyway.

History:
 * 0.2: Made it working with newer Mediawiki, having the UserMailer class: Objects for email addresses and changed order of from and to address. Thanks to the people commenting on the discussion page.
 * 0.1: Initial Version

''This is not thouroughly tested. There is a version that works with MediaWiki 1.8 and newer and an older one that was tested with MediaWiki 1.5.7. The only difference between the versions lies in 0.2 using the UserMailer and MailAddress classes as required by newer MediaWiki. (If somebody knows in which version the userMailer function started requiring MailAddress objects, please add that information here.) If you have any questions/comments, please send the author an email.''

Installation
To activate the extension, put the code into a file in your MediaWiki installation and include it from your LocalSettings.php with: include("$IP/extensions/FormHandler.php");

To avoid spam, you should make sure that only trusted users can edit the pages which use the extension.

Syntax
Version 0.1 and 0.2 support the field types text, textarea and select. Additionally hidden can be used to pass additional information with the Email. The syntax is very simple: [type]:(*) [param]="[value]", with the *, you mark entries which are required, the rest is considered optional. The form is included with the extension tag. It has some attributes to configure the form:

It is an error to not set at least one of sender or email.
 * name: A name to identify the form, useful if you use different forms on a page (required)
 * method: tells how to treat data (for now, only email is implemented) (required)
 * target: target for this form (with method email, this is the email address and required)
 * submit: if present, defines the text of the submit button, otherwise it is "Submit"
 * reset: if present, adds a reset button with its value as caption. Otherwise, no reset button is provided with the form.
 * email: if present, an email field is added to the top of the form with this attributes value as prompt. It is used as reply-to when sending the form. If sender is not set, it is also used as 'from' address.
 * sender: if present, must be a valid email address which is used as 'from' address to avoid problem with user specified email address. If it is present, it is used as 'from' instead of the user suplied email address in the email field.

An Example
 hidden: name="testform" value="additional info" text:* name="name" prompt="Your RealName" select: name="category" prompt="Please select problem category" option="Linux Software" option="Linux Hardware" text:* name="summary" prompt="Problem summary" textarea: name="description" prompt="Problem description" rows="10" cols="50" select: name="priority" prompt="Priority" option="Low" option="Medium" option="High" value="Medium"

Implementation
Hidden fields are not passed to the client at all, but sent as defined in the wiki page. This avoids users changing them. If you have a reasonable example why this could be a problem, i can happily change the behaviour.

Known Bugs
There is a problem with server side caching of the output of our extension. For now, we pass action=purge with every request which seems to help.

Todo

 * Develop a security concept. It must ensure that only trusted users can use the extension in the wiki pages. At the very last, a configuration option should limit the possible addresses to send form data to. (This however would require the admin to edit the php file, which is complicated.)
 * Add more supported field types, e.g. radio and checkbox
 * It would be easy to implement writing to a file or into into a database.

Code of Form Handler 0.2 (Mediawiki 1.8 and newer)
For old versions of Mediawiki, please see below for Form Handler 0.1.

Copy the following into a file named extensions/FormHandler.php

';   return $output; }

function submit { global $wgUser, $wgDBname, $wgIP; $error = ''; foreach($this->fields as $field) { $this->fields[$field['name']]['value'] = $this->request->getText('FormHandler_'.$field['name']); if (isset($field['required'])) { if (empty($_POST['FormHandler_'.$field['name']])) { $error .= $field['prompt']. ' '; //todo: better would be to highlight the fields. for this we would keep a list of required fields here. }     }    }    if (! empty($error)) { return $this->show("Not all required fields have been filled out: \n$error"); }

if ( 0 != $wgUser->getID ) { $username = $wgUser->getName; } else { $username = '(not logged in)'; }

$usermail = $this->request->getText('FormHandlerEmail'); if (empty($usermail)) $usermail=false;

$message = 'Form '.$this->argv['name']." has been submitted by $username (IP: $wgIP, Email: " . ($usermail ? $usermail : 'not specified') .') This Email is sent to you by MediaWiki FormHandler extension from http://'.$_SERVER['SERVER_NAME'].$_SERVER['PHP_SELF']."\n\n"; foreach($this->fields as $field) { $message .= $field['name']. ': ';     switch($field['type']) { case 'text': case 'select': case 'textarea': $value = $this->request->getText('FormHandler_'.$field['name']); break; case 'hidden': $value = $field['value']; //we do not put it into form and not treat it, but keep it at server side... break; case 'invalid': $value = 'There is an invalid line in the form: '.$field['value']; break; default: $value = 'Implementation Error in FormHandler: unexpected field type '.$field['type']; break; }     $message .= (empty($value) ? '[not set]' : $value). "\n"; }

switch ($this->argv['method']) { case 'email': require_once('UserMailer.php'); if ($usermail!==false && ! $this->isValidEmail($usermail)) return $this->show('Your specified Email adress is invalid: '.$usermail); //sender is either == usermail or tested above

if (! $this->sender) { if (! $usermail) return $this->show("The Email field is required, please fill in."); $this->sender=$usermail; }

//16.4.2008: use new mailer class. new order $to, $from //fixme: there are no sanity checks for email adresses, neither here nor in MailAddress $error = UserMailer::send(new MailAddress($this->target), 			    new MailAddress($this->sender)			     'Contact form '.$this->argv['name'],			     $message,			     new MailAddress($usermail)); if (empty($error)) { return 'Thank you for sending a message to '.$this->target."

\n&lt;pre>".nl2br($message).'&lt;/pre>';	} else {	 return "Sorry, sending the form failed.\n" . htmlspecialchars($error);	}	break;      default:	return 'Sorry, this is an invalid form, i do not know the method to store the information: '.$this->argv['method'];    }  }  /*    * Check Email for validity, using a regular expression.   */    function isValidEmail($candidate) {    return (eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$", $candidate));  } }

Code of Form Handler 0.1 (Mediawiki 1.5.7 and others)
Copy the following into a file named extensions/FormHandler.php

';   return $output; }

function submit { global $wgUser, $wgDBname, $wgIP; $error = ''; foreach($this->fields as $field) { $this->fields[$field['name']]['value'] = $this->request->getText('FormHandler_'.$field['name']); if (isset($field['required'])) { if (empty($_POST['FormHandler_'.$field['name']])) { $error .= $field['prompt']. ' '; //todo: better would be to highlight the fields. for this we would keep a list of required fields here. }     }    }    if (! empty($error)) { return $this->show("Not all required fields have been filled out: \n$error"); }

if ( 0 != $wgUser->getID ) { $username = $wgUser->getName; } else { $username = '(not logged in)'; }

$usermail = $this->request->getText('FormHandlerEmail'); if (empty($usermail)) $usermail=false;

$message = 'Form '.$this->argv['name']." has been submitted by $username (IP: $wgIP, Email: " . ($usermail ? $usermail : 'not specified') .') This Email is sent to you by MediaWiki FormHandler extension from http://'.$_SERVER['SERVER_NAME'].$_SERVER['PHP_SELF']."\n\n"; foreach($this->fields as $field) { $message .= $field['name']. ': ';     switch($field['type']) { case 'text': case 'select': case 'textarea': $value = $this->request->getText('FormHandler_'.$field['name']); break; case 'hidden': $value = $field['value']; //we do not put it into form and not treat it, but keep it at server side... break; case 'invalid': $value = 'There is an invalid line in the form: '.$field['value']; break; default: $value = 'Implementation Error in FormHandler: unexpected field type '.$field['type']; break; }     $message .= (empty($value) ? '[not set]' : $value). "\n"; }

switch ($this->argv['method']) { case 'email': require_once('UserMailer.php'); if ($usermail!==false && ! $this->isValidEmail($usermail)) return $this->show('Your specified Email adress is invalid: '.$usermail); //sender is either == usermail or tested above

if (! $this->sender) { if (! $usermail) return $this->show("The Email field is required, please fill in."); $this->sender=$usermail; }

$error = userMailer( $this->sender, 			    $this->target, 			     'Contact form '.$this->argv['name'],			     $message,			     $usermail); if (empty($error)) { return 'Thank you for sending a message to '.$this->target."

\n&lt;pre>".nl2br($message).'&lt;/pre>';	} else {	 return "Sorry, sending the form failed.\n" . htmlspecialchars($error);	}	break;      default:	return 'Sorry, this is an invalid form, i do not know the method to store the information: '.$this->argv['method'];    }  }  /*    * Check Email for validity, using a regular expression.   */    function isValidEmail($candidate) {    return (eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$", $candidate));  } }