'Form submitted from website: %s',
'submitted_by' => 'Visitor IP address: %s',
'too_many_submissions' => 'Too many recent submissions from this IP',
'failed_to_send_email' => 'Failed to send email',
'invalid_field_type' => 'Unknown field type \'%s\'.',
'invalid_form_config' => 'Field \'%s\' has an invalid configuration.',
'unknown_method' => 'Unknown server request method'
);
public function __construct() {}
public function process($form)
{
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
die($this->_getErrorResponse($this->_messages['unknown_method']));
}
if ($this->checkTooManySubmissions($_SERVER['REMOTE_ADDR'])) {
die($this->_getErrorResponse($this->_messages['too_many_submissions']));
}
// will die() if there are any errors
$this->_checkRequiredFields($form);
// will die() if there is a send email problem
$this->_formSubmission($form);
}
public function checkTooManySubmissions($ip)
{
$tooManySubmissions = false;
try {
if (in_array("sqlite", PDO::getAvailableDrivers(), TRUE)) {
$db = new PDO('sqlite:muse-throttle-db.sqlite3');
} else if (function_exists("sqlite_open")) {
$db = new PDO('sqlite2:muse-throttle-db');
} else {
return false;
}
} catch(PDOException $Exception) {
return $tooManySubmissions;
}
if ($db)
{
$res = $db->query("SELECT 1 FROM sqlite_master WHERE type='table' AND name='Submission_History';");
if (!$res or $res->fetchColumn() == 0)
{
$db->exec("CREATE TABLE Submission_History (IP VARCHAR(39), Submission_Date TIMESTAMP)");
}
$db->exec("DELETE FROM Submission_History WHERE Submission_Date < DATETIME('now','-2 hours')");
$stmt = $db->prepare("INSERT INTO Submission_History (IP,Submission_Date) VALUES (:ip, DATETIME('now'))");
$stmt->bindParam(':ip', $ip);
$stmt->execute();
$stmt->closeCursor();
$stmt = $db->prepare("SELECT COUNT(1) FROM Submission_History WHERE IP = :ip;");
$stmt->bindParam(':ip', $ip);
$stmt->execute();
if ($stmt->fetchColumn() > 25) {
$tooManySubmissions = true;
}
// Close file db connection
$db = null;
}
return $tooManySubmissions;
}
private function _checkRequiredFields($form)
{
$errors = array();
foreach ($form['fields'] as $field => $properties) {
if (!$properties['required']) {
continue;
}
if (strpos($field, ' ')) {
$field = str_replace(' ', '_', $field);
}
if (!array_key_exists($field, $_REQUEST) || ($_REQUEST[$field] !== "0" && empty($_REQUEST[$field]))) {
array_push($errors, array('field' => $field, 'message' => $properties['errors']['required']));
} else if (!$this->_checkFieldValueFormat($field, $properties)) {
array_push($errors, array('field' => $field, 'message' => $properties['errors']['format']));
}
}
if (!empty($errors)) {
die($this->_getErrorResponse(array('fields' => $errors)));
}
}
private function _checkFieldValueFormat($field, $properties)
{
$value = $this->_getFormFieldValue($field, $properties);
switch($properties['type']) {
case 'checkbox':
case 'tel':
case 'string':
// no format to validate for those fields
return true;
case 'email':
return 1 == preg_match('/^[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i', $value);
default:
die($this->_getErrorResponse(sprintf($this->_messages['invalid_field_type'], $properties['type'])));
}
}
private function _getFormFieldValue($field, $properties)
{
$value = isset($_REQUEST[$field]) ? $_REQUEST[$field] : '';
switch($properties['type']) {
case 'checkbox':
return $value ? $value : '';
case 'string':
case 'tel':
case 'email':
$returnValues = '';
if (is_array($value)) {
foreach ($value as $key => $val) {
$returnValues .= $this->_encodeValue($val);
if ($key !== count($value) - 1) {
$returnValues .= ', ';
}
}
} else {
$returnValues = $this->_encodeValue($value);
}
return $returnValues;
default:
die($this->_getErrorResponse(sprintf($this->_messages['invalid_field_type'], $properties['type'])));
}
}
private function _formSubmission($form)
{
$emailFrom = $form['email']['from'];
$formEmail = $emailFrom ? $emailFrom : ((array_key_exists('email', $_REQUEST) && !empty($_REQUEST['email'])) ? $this->_cleanupEmail($_REQUEST['email']) : '');
$to = $form['email']['to'];
$subject = $form['subject'];
$message = $this->_getEmailBody($subject, $form['email_message'], $form['fields']);
$headers = $this->_getEmailHeaders($to, $formEmail);
$sent = @mail($to, $subject, $message, $headers);
if(!$sent) {
die($this->_getErrorResponse($this->_messages['failed_to_send_email']));
}
$success_data = array(
'redirect' => $form['success_redirect']
);
echo $this->_getFormResponse(true, $success_data);
}
private function _getEmailHeaders($toEmail, $formEmail) {
$headers = 'From: ' . $toEmail . PHP_EOL;
$headers .= 'Reply-To: ' . $formEmail . PHP_EOL;
$headers .= 'X-Mailer: PHP/' . phpversion() . PHP_EOL;
$headers .= 'Content-type: text/html; charset=utf-8' . PHP_EOL;
return $headers;
}
private function _getEmailBody($subject, $emailMsg, $fields) {
$message = '';
$message .= '
' . $this->_encodeValue($subject) . '';
$styles = <<
th, td, caption {
font-weight: 400;
vertical-align: top;
text-align: left;
}
STYLES;
$message .= $styles;
$message .= '';
$message .= '';
$message .= '';
$message .= '';
$message .= '';
$message .= '';
$message .= '';
$message .= '';
$message .= '';
$message .= $emailMsg;
$message .= ' | ';
$message .= '';
$message .= '';
$message .= '';
$message .= '';
$message .= '';
$sortedFields = array();
foreach ($fields as $field => $properties) {
array_push($sortedFields, array('field' => $field, 'properties' => $properties));
}
// sort fields
usort($sortedFields, array(&$this, '_fieldComparer'));
foreach ($sortedFields as $fieldWrapper) {
$message .= '';
$message .= '' . $this->_encodeValue($fieldWrapper['properties']['label']) . ':';
$message .= '' . $this->_getFormFieldValue($fieldWrapper['field'], $fieldWrapper['properties']) . ' ';
$message .= ' | ';
}
$message .= ' ';
$message .= ' | ';
$message .= '';
$message .= '';
$message .= ' ' . sprintf($this->_messages['submitted_from'], $this->_encodeValue($_SERVER['SERVER_NAME'])) . ' ';
$message .= '' . sprintf($this->_messages['submitted_by'], $this->_encodeValue($_SERVER['REMOTE_ADDR'])) . ' ';
$message .= ' | ';
$message .= ' ';
$message .= ' | ';
$message .= ' | ';
$message .= ' | ';
$message .= ' |
';
$message .= '