to be more robust and configurable // 2003-02-21 - 1.0 - First rev // 2003-02-22 - 1.1 - Change to allow relative paths to params file. // 2003-03-04 - 1.2 - Allow format file for customized text body. Added ValidateFile function // 2003-03-04 - 1.3 - fix problem with required field warning text // 2003-03-04 - 1.4 - fix problems with SendEmail and added MyExplode // 2003-03-07 - 1.5 - added function to GetFormatFile. Format file can now also be the params file. // Added ability to have a field be the sender address // Added ability to define the ack email sender to be different than the primary sender // Added ability to define the ack email subject // 2003-06-10 - 1.6 - Added version header & vhost header for tracking // 2003-10-14 - 1.7 - added missing init of maxIters in ParseFormatData // 2004-02-24 - 1.8 - Added error checking on including params_file // 2004-04-14 - 1.9 - imploded array based form params using tab characters // 2004-06-24 - 2.0 - moved pass-by-reference symbols to function delclaration for ValidateRecipLists // fixed problem with required_missing_redirect // 2004-09-21 - 2.1 - changed GLOBALS references to use _SERVER // Fixed ValidateFile to better determine file location // 2005-01-25 - 2.2 - Fixed ValidateFile to better determine file location. MyExplode -> explode // removed dependency on register_globals for GetFormParam // define('kVersion', '2.2'); $errors = ''; $FormData = $_POST; // var_dump($FormData); // exit(); // now extract any values that might have been posted which we don't allow to prevent being a relay // these values should come across in the params file that is included later, but we will take no chances. unset($sender, $TOrecipients, $CCrecipients, $BCCrecipients); // try and prevent people snooping around up above doc root $paramsFile = ValidateFile($FormData['params_file'], 'Parameters'); unset($FormData['params_file']); // by including the params file, where the options are set in a php code block // we are preventing this form mail from being a relay. ini_set('track_errors', true); $formatMode = 0; if(! @include($paramsFile)) { if (!empty($php_errormsg)) print_error("Something is wrong with your parameters file:
$php_errormsg", ''); } ini_restore('track_errors'); if (empty($sender) && empty($sender_field)) print_error("No sender parameter defined.", 'missing'); $senderAddr = $sender; if (!empty($sender_field)) { $tmpSender = $FormData[$sender_field]; if (isEmailAddress($tmpSender)) { $senderAddr = $tmpSender; } else { $errors .= "\nSender address field data not valid: $tmpSender\n"; if (!isEmailAddress($sender)) { $senderAddr = 'website@'.$_SERVER['HTTP_HOST']; $errors .= "\nNo valid Sender address found.\n"; } } } // validate recipient lists. this function also turns the recip vars into arrays $InvalidRecipErrs = ValidateRecipLists($TOrecipients, $CCrecipients, $BCCrecipients); if ( !empty($InvalidRecipErrs) ) { print_error(implode("\n", $InvalidRecipErrs), 'missing'); } $required_missing_redirect = $FormData['required_missing_redirect']; // handle the required fields if (!empty($require)) { $missing_field_list = ''; // seperate at the commas $require = ereg_replace( ' +', '', $require); $required = MyExplode(',',$require); foreach($required as $reqFld) { // check if they exsist if ( !isset($FormData[$reqFld]) || (trim($FormData[$reqFld]) == '') ) { // if the required_missing_redirect option is on: redirect them if ($required_missing_redirect) { header ("Location: $required_missing_redirect"); exit(); } $missing_field_list .= "Missing: $reqFld
\n"; } } // send error to our mighty error function if (!empty($missing_field_list)) print_error($missing_field_list,"missing"); } // banned emails, these will be email addresses of people // who are blocked from using the script if (!empty($banlist) && !is_array($banlist)) $banlist = MyExplode(',', $banlist); if (empty($banlist)) $banlist = array(); $banlist[] = '*@somedomain.com'; $banlist[] = 'user@domain.com'; $banlist[] = 'etc@domains.com'; if (!empty($email_verify)) { $VerifyFields = MyExplode(',',$email_verify); foreach($VerifyFields as $theFld) { $emailToVerify = trim($FormData[$theFld]); if (!empty($emailToVerify) && !isEmailAddress($emailToVerify)) print_error("Email Address $emailToVerify is invalid"); if ( ! CheckBanlist($banlist, $emailToVerify) ) { print_error("You are using a banned email address."); } $FormData[$theFld] = $emailToVerify; } } // check zipcodes for validity if (!empty($zip_verify)) { $VerifyFields = MyExplode(',',$zip_verify); foreach($VerifyFields as $theFld) { $zipToVerify = trim($FormData[$theFld]); if (!empty($zipToVerify) && (!ereg("(^[0-9]{5})-([0-9]{4}$)", trim($zipToVerify)) && (!ereg("^[a-zA-Z][0-9][a-zA-Z][[:space:]][0-9][a-zA-Z][0-9]$", trim($zipToVerify))) && (!ereg("(^[0-9]{5})", trim($zipToVerify)))) ) print_error("Zip/Postal code $zipToVerify is invalid"); $FormData[$theFld] = $zipToVerify; } } // check phone for validity if (!empty($phone_verify)) { $VerifyFields = MyExplode(',',$phone_verify); foreach($VerifyFields as $theFld) { $phoneToVerify = trim($FormData[$theFld]); if (!empty($phoneToVerify) && (!ereg("(^(.*)[0-9]{3})(.*)([0-9]{3})(.*)([0-9]{4}$)", $phoneToVerify)) ) print_error("Phone Number $phoneToVerify is invalid"); $FormData[$theFld] = $phoneToVerify; } } if (!empty($format_file)) { $formatFile = ValidateFile($format_file, 'Format'); $content = ParseFormatFile($formatFile, $FormData); } else { // prepare the content $content = ParseForm($FormData); } // check for a file if there is a file upload it if ($file_name) { if ($file_size > 0) { if (!ereg("/$", $path_to_file_uploads)) $path_to_file_uploads = $path_to_file_uploads.'/'; $location = $path_to_file_uploads.$file_name; if (file_exists($path_to_file_uploads.$file_name)) $location .= '.new'; copy($file,$location); unlink($file); $content .= 'Uploaded File: '.$location."\n"; } } // second file. if ($file2_name) { if ($file2_size > 0) { if (!ereg("/$", $path_to_file_uploads)) $path_to_file_uploads = $path_to_file_uploads."/"; $location = $path_to_file_uploads.$file2_name; if (file_exists($path_to_file_uploads.$file2_name)) $location .= ".new"; copy($file2,$location); unlink($file2); $content .= "Uploaded File: ".$location."\n"; } } // if the env_report option is on: get eviromental variables if ($env_report) { $env_report = ereg_replace(' +', '', $env_report); $env_reports = MyExplode(',',$env_report); $content .= "\n------ environmental variables ------\n"; foreach($env_reports as $envrptFld) { $envrptFld = trim($envrptFld); switch ($envrptFld) { case 'REMOTE_HOST': $content .= 'REMOTE HOST: '.$_SERVER['REMOTE_HOST']."\n"; break; case 'REMOTE_USER': $content .= 'REMOTE USER: '.$_SERVER['REMOTE_USER']."\n"; break; case 'REMOTE_ADDR': $content .= 'REMOTE ADDR: '.$_SERVER['REMOTE_ADDR']."\n"; break; case 'HTTP_USER_AGENT': $content .= 'BROWSER: '.$_SERVER['HTTP_USER_AGENT']."\n"; break; } } } // if the subject option is not set: set the default if (!$subject) $subject = $_SERVER['HTTP_HOST']. " Form submission"; if (!empty($ack_email_to_field)) { if (!empty($ack_email_sender) && isEmailAddress($ack_email_sender)) { $content .= "\nAcknowledgment email sender address not valid: $ack_email_sender\n"; $ack_email_sender = ''; } $ackEmailTo = $FormData[$ack_email_to_field]; if ( ! isEmailAddress($ackEmailTo) ) { $content .= "\nAcknowledgment email address not valid: $ackEmailTo\n"; $ackEmailTo = ''; // signal not to send email } if ( ! CheckBanlist($banlist, $ackEmailTo) ) { $content .= "\nAcknowledgment email address banned: $ackEmailTo\n"; $ackEmailTo = ''; // signal not to send email } if (!empty($ack_email_msg_file) && ($ack_email_msg_file == ValidateFile($ack_email_msg_file))) { // allows a user to put data and formdata items into a "format" file so the ack message // can be customized. $ack_email_msg = ParseFormatFile($ack_email_msg_file, $FormData); } if (empty($ack_email_msg)) $ack_email_msg = "Your form submission was accepted.\n\n Thank You."; if (empty($ack_email_subject)) $ack_email_subject = "Your form submission was sent"; if (!empty($ackEmailTo)) { if (empty($ack_email_sender)) $ack_email_sender = $senderAddr; SendEmail($ack_email_sender, $ackEmailTo, '', '', $ack_email_subject, $ack_email_msg); } } $content .= $errors; SendEmail($senderAddr, $TOrecipients, $CCrecipients, $BCCrecipients, $subject, $content); // send it off // mail_it(stripslashes($content), stripslashes($subject), $email, $recipient, $allowed_email_recipients_array); // if the redirect option is set: redirect them if ($redirect) { header ("Location: $redirect"); } else { echo "Thank you for your submission\n"; echo "

\n"; } exit(); // <---------- THE END ----------> // // Functions only below // our mighty error function.. function print_error($reason,$type = 0) { build_body($title, $bgcolor, $text_color, $link_color, $vlink_color, $alink_color, $style_sheet); // for missing required data if ($type == "missing") { echo "The form was not submitted because of missing information:

\n"; echo "

"; echo "Please use your browser's back button to return to the form and try again."; } else { // every other error echo "The form was not submitted because of the following reasons:

"; echo "

"; } echo "

\n"; exit(); } function isEmailAddress($email) { return eregi("^[a-z0-9]([_\\.\\-]?[a-z0-9]+)*@((([a-z0-9]+[a-z0-9\\-]*[a\-z0-9]+)|[a-z0-9])+\\.)+[a-z]{2,10}$", $email); } function ValidateRecipLists(&$TOrecipients, &$CCrecipients, &$BCCrecipients) { $InvalidRecips = array(); $totalRecips = $validRecips = 0; if (!is_array($TOrecipients)) $TOrecipients = MyExplode(',',$TOrecipients); if (!is_array($CCrecipients)) $CCrecipients = MyExplode(',',$CCrecipients); if (!is_array($BCCrecipients)) $BCCrecipients = MyExplode(',',$BCCrecipients); $AllRecipLists = array('To' => $TOrecipients, 'CC' => $CCrecipients, 'BCC' => $BCCrecipients); foreach($AllRecipLists as $type => $RecipLists) { foreach($RecipLists as $emailAddr) { $totalRecips++; if (! isEmailAddress($emailAddr)) { $InvalidRecips[] = "Invalid Recipient - $type: $emailAddr"; } else $validRecips++; } } return $InvalidRecips; } // function to check the banlist // suggested by a whole lot of people.. Thanks function CheckBanlist($banlist, $email) { $allow = true; foreach($banlist as $banned) { $temp = MyExplode('@', $banned); if ($temp[0] == '*') { $temp2 = MyExplode('@', $email); if (trim(strtolower($temp2[1])) == trim(strtolower($temp[1]))) $allow = false; } else { if (trim(strtolower($email)) == trim(strtolower($banned))) $allow = false; } } // if (!$allow) print_error("You are using a banned email address."); return $allow; } //PATH_TRANSLATED function ValidateFile($theFile, $errTitle) { // A file must be defined using a full path from the doc root or // a single file name that is in same dir as the referring script or this file $siteDocRoot = $_SERVER['DOCUMENT_ROOT']; $outFile = ''; $fileBaseName = basename($theFile); if (! ereg('^/', $theFile)) // path does not start with a "/" { // we have to figure out the path of the original caller script file $referFile = $_SERVER['HTTP_REFERER']; if (!empty($referFile)) { $referFile = explode('/', $referFile, 4); // check to see that the host part of the referrer is the same as our current host $myHost = $_SERVER['HTTP_HOST']; if (($referFile[2] == $myHost) && !empty($referFile[4])) { $outFile = dirname($siteDocRoot .'/'. $referFile[4]) .'/'. $fileBaseName; } } } else $outFile = $siteDocRoot . $theFile; if (empty($outFile)) // not immediately obvious where file is { // so assume it is in the same directory as this script $outFile = dirname(__FILE__) .'/'. $fileBaseName; } if (! file_exists($outFile)) print_error("$errTitle File Given: <$theFile> not found.\n$outFile", 'missing'); if (! is_readable($outFile)) print_error("$errTitle File Given: <$theFile> not readable (perm). $outFile", 'missing'); return $outFile; } // parse the form and create the content string which we will send function ParseForm($FormData) { // build reserved keyword array $reserved_keys[] = "MAX_FILE_SIZE"; $reserved_keys[] = "required"; $reserved_keys[] = "redirect"; $reserved_keys[] = "email"; $reserved_keys[] = "require"; $reserved_keys[] = "path_to_file"; $reserved_keys[] = "recipient"; $reserved_keys[] = "subject"; $reserved_keys[] = "bgcolor"; $reserved_keys[] = "text_color"; $reserved_keys[] = "link_color"; $reserved_keys[] = "vlink_color"; $reserved_keys[] = "alink_color"; $reserved_keys[] = "title"; $reserved_keys[] = "missing_fields_redirect"; $reserved_keys[] = "env_report"; if (count($FormData)) { foreach($FormData as $key => $val) { // exclude reserved keywords $reserved_violation = 0; foreach($reserved_keys as $curRsvdWrd) { if ($key == $curRsvdWrd) $reserved_violation = 1; break; } // prepare content if ($reserved_violation != 1) { if (is_array($val)) { foreach($val as $contentVal) $content .= "$key: $contentVal\n"; } else $content .= "$key: $val\n"; } } } return $content; } function ReadFileData($theFile) { $fp = fopen($theFile, 'r'); $fileData = fread($fp, filesize($theFile)); fclose($fp); return $fileData; } function GetIncludeFile($theFile) { ob_start(); @include($theFile); $data = ob_get_contents(); ob_end_clean(); return $data; } function GetFormatFile($theFile) { $formatMode = 1; ob_start(); @include($theFile); $data = ob_get_contents(); ob_end_clean(); return $data; } function ParseFormatFile($formatFile, $FormData) { // get the data from the format file $formatFileData = GetFormatFile($formatFile); // determine line endings of the format file. $numLFLines = count(MyExplode("\n", $formatFileData)); $numCRLines = count(MyExplode("\r", $formatFileData)); $numCRLFLines = count(MyExplode("\r\n", $formatFileData)); $maxLines = max($numLFLines, $numCRLines, $numCRLFLines); if ($numCRLFLines == $maxLines) $FormatData = MyExplode("\r\n", $formatFileData); if ($numCRLines == $maxLines) $FormatData = MyExplode("\r", $formatFileData); if ($numLFLines == $maxLines) $FormatData = MyExplode("\n", $formatFileData); $maxIters = 200; foreach($FormatData as $lineNum => $lineText) { // echo $lineText .'
'; foreach(range(1,$maxIters) as $i) { $formParam = preg_split ('#\[formdata:\s*?\'(.+?)\'\]#', $lineText, 0, PREG_SPLIT_DELIM_CAPTURE); if ($formParam[0] == $lineText) break; $paramText = $FormData[$formParam[1]]; if (is_array($paramText)) $paramText = implode("\t", $paramText); $lineText = preg_replace ('#\[formdata:\s*?\'(.+?)\'\]#', $paramText, $lineText, 1); } foreach(range(1,$maxIters) as $i) { $formParam = preg_split ('#\[form_param:\s*?\'(.+?)\'\]#', $lineText, 0, PREG_SPLIT_DELIM_CAPTURE); if ($formParam[0] == $lineText) break; $paramText = $FormData[$formParam[1]]; if (is_array($paramText)) $paramText = implode("\t", $paramText); $lineText = preg_replace ('#\[form_param:\s*?\'(.+?)\'\]#', $paramText, $lineText, 1); } foreach(range(1,$maxIters) as $i) { $formParam = preg_split ('|\[formparam: \'(.+?)\'\]|', $lineText, 0, PREG_SPLIT_DELIM_CAPTURE); if ($formParam[0] == $lineText) break; $paramText = GetFormParam($formParam[1]); if (is_array($paramText)) $paramText = implode("\t", $paramText); $lineText = preg_replace ('|\[formparam: \'(.+?)\'\]|', $paramText, $lineText, 1); } // echo $lineText .'
'; $FormatData[$lineNum] = $lineText; } return implode("\n", $FormatData); } function GetFormParam($theParam) { $theData = $_REQUEST[$theParam]; if (is_array($theData)) $theData = implode(',', $theData); return $theData; } function SendEmail($fromAddress, $recipTo, $recipCC, $recipBCC, $subject, $msg) { if (!is_array($recipTo)) $recipTo = MyExplode(',', $recipTo); if (!is_array($recipCC)) $recipCC = MyExplode(',', $recipCC); if (!is_array($recipBCC)) $recipBCC = MyExplode(',', $recipBCC); $recipList = ''; foreach($recipTo as $recipAddr) { if (!empty($recipList)) $recipList .= ', '; $recipList .= $recipAddr; } $infoHeaders = ''; $infoHeaders .= "From: <$fromAddress>\r\n"; $infoHeaders .= 'Date: '. date('r') ."\r\n"; $recipHeaders = ''; $recipHeaders .= AddRecipHeader($recipCC, 'Cc'); $recipHeaders .= AddRecipHeader($recipBCC, 'Bcc'); $emailHeaders = 'X-Version: MacServe.net Formmail.php v.'. kVersion ."\r\n"; $emailHeaders = 'X-VHost: '. $_SERVER['HTTP_HOST'] ."\r\n"; $allHeaders = $infoHeaders . $recipHeaders . $emailHeaders; $extraParams = '-f'.$fromAddress; // make sure the default sendmail config is going to parse for addresses. if (! strstr(ini_get('sendmail_path'), '-t')) $extraParams = '-t '. $extraParams; // echo $subject .'
'; // echo $recipList .'
'; // echo $msg .'
'; // echo $allHeaders .'
'; // echo $extraParams .'
'; $sendResult = mail($recipList, $subject, $msg, $allHeaders, $extraParams); return $sendResult; } function AddRecipHeader($RecipList, $recipType) { if (count($RecipList) == 0) return ''; $recipHeader = "$recipType: "; $numRecips = 0; foreach($RecipList as $recipAddr) { if (empty($recipAddr)) continue; $numRecips++; if ($numRecips > 1) $recipHeader .= ",\r\n "; $recipHeader .= $recipAddr; } $recipHeader .= "\r\n"; return $recipHeader; } // take in the body building arguments and build the body tag for page display function build_body($title, $bgcolor, $text_color, $link_color, $vlink_color, $alink_color, $style_sheet) { if ($style_sheet) echo "\n"; if ($title) echo "$title\n"; if (!$bgcolor) $bgcolor = "#FFFFFF"; if (!$text_color) $text_color = "#000000"; if (!$link_color) $link_color = "#0000FF"; if (!$vlink_color) $vlink_color = "#FF0000"; if (!$alink_color) $alink_color = "#000088"; if ($background) $background = "background=\"$background\""; echo "\n\n"; } function MyExplode($theDelim, $theData) { if (empty($theData)) return array(); return explode($theDelim, $theData); } return; ?>