Skip to Content

Formmail

]*?>/i’,$s_line_feed,$s_str);
//
// replace breaks with new lines (line feeds)
//
$s_str = preg_replace(‘//i’,$s_line_feed,$s_str);
//
// overcome this bug: http://bugs.php.net/bug.php?id=21311
//
$s_str = preg_replace(‘/]*>/s’,”,$s_str);
//
// get rid of all HTML tags
//
$s_str = strip_tags($s_str);
return ($s_str);
}

//
// Check for valid URL in TARGET_URLS
//
function CheckValidURL($s_url)
{
global $TARGET_URLS;

foreach ($TARGET_URLS as $s_prefix)
if (!empty($s_prefix) &&
strtolower(substr($s_url,0,strlen($s_prefix))) ==
strtolower($s_prefix))
return (true);
return (false);
}

//
// Scan the given data for fields returned from the CRM.
// A field has this following format:
// __FIELDNAME__=value
// terminated by a line feed.
//
function FindCRMFields($s_data)
{
$a_ret = array();
if (preg_match_all(‘/^__([A-Za-z][A-Za-z0-9_]*)__=(.*)$/m’,$s_data,$a_matches) === false)
SendAlert(GetMessage(MSG_PREG_FAILED));
else
{
$n_matches = count($a_matches[0]);
// SendAlert(“$n_matches on ‘$s_data'”);
for ($ii = 0 ; $ii < $n_matches ; $ii++)
if (isset($a_matches[1][$ii]) && isset($a_matches[2][$ii]))
$a_ret[$a_matches[1][$ii]] = $a_matches[2][$ii];
}
return ($a_ret);
}

//
// open the given URL to send data to it, we expect the response
// to contain at least ‘__OK__=’ followed by true or false
//
function SendToCRM($s_url,&$a_data)
{
global $php_errormsg;

if (!CheckValidURL($s_url))
{
SendAlert(GetMessage(MSG_URL_INVALID,array(“URL”=>$s_url)));
return (false);
}
@ $fp = fopen($s_url,”r”);
if ($fp === false)
{
SendAlert(GetMessage(MSG_URL_OPEN,array(“URL”=>$s_url,
“ERROR”=>CheckString($php_errormsg))));
return (false);
}
$s_mesg = “”;
while (!feof($fp))
{
$s_line = fgets($fp,4096);
$s_mesg .= $s_line;
}
fclose($fp);
$s_mesg = StripHTML($s_mesg);
$s_result = preg_match(‘/__OK__=(.*)/’,$s_mesg,$a_matches);
if (count($a_matches) < 2 || $a_matches[1] === “”)
{
//
// no agreed __OK__ value returned – assume system error
//
SendAlert(GetMessage(MSG_CRM_FAILED,array(“URL”=>$s_url,
“MSG”=>$s_mesg)));
return (false);
}
//
// look for fields to return
//
$a_data = FindCRMFields($s_mesg);
//
// check for success or user error
//
switch (strtolower($a_matches[1]))
{
case “true”:
break;
case “false”:
//
// check for user error
//
if (isset($a_data[“USERERRORCODE”]))
{
$s_error_code = “crm_error”;
$s_error_mesg = GetMessage(MSG_CRM_FORM_ERROR);
$s_error_code .= $a_data[“USERERRORCODE”];
if (isset($a_data[“USERERRORMESG”]))
$s_error_mesg = $a_data[“USERERRORMESG”];
UserError($s_error_code,$s_error_mesg);
// no return
}
return (false);
}
return (true);
}

//
// Split into field name and friendly name; returns an array with
// two elements.
// Format is:
// fieldname:Nice printable name for displaying
//
function GetFriendlyName($s_name)
{
if (($i_pos = strpos($s_name,’:’)) === false)
return (array(trim($s_name),trim($s_name)));
return (array(trim(substr($s_name,0,$i_pos)),trim(substr($s_name,$i_pos+1))));
}

define(“REQUIREDOPS”,”|^!=”); // operand characters for advanced required processing

//
// Perform a field comparison test.
//
function FieldTest($s_oper,$s_fld1,$s_fld2,$a_vars,&$s_error_mesg,
$s_friendly1 = “”,$s_friendly2 = “”)
{
$b_ok = true;
//
// perform the test
//
switch ($s_oper)
{
case ‘&’: // both fields must be present
if (!TestFieldEmpty($s_fld1,$a_vars,$s_empty1) &&
!TestFieldEmpty($s_fld2,$a_vars,$s_empty2))
; // OK
else
{
//
// failed
//
$s_error_mesg = GetMessage(MSG_AND,array(“ITEM1″=>$s_friendly1,
“ITEM2″=>$s_friendly2));
$b_ok = false;
}
break;
case ‘|’: // either field or both must be present
if (!TestFieldEmpty($s_fld1,$a_vars,$s_empty1) ||
!TestFieldEmpty($s_fld2,$a_vars,$s_empty2))
; // OK
else
{
//
// failed
//
$s_error_mesg = GetMessage(MSG_OR,array(“ITEM1″=>$s_friendly1,
“ITEM2″=>$s_friendly2));
$b_ok = false;
}
break;
case ‘^’: // either field but not both must be present
$b_got1 = !TestFieldEmpty($s_fld1,$a_vars,$s_empty1);
$b_got2 = !TestFieldEmpty($s_fld2,$a_vars,$s_empty2);
if ($b_got1 || $b_got2)
{
if ($b_got1 && $b_got2)
{
//
// failed
//
$s_error_mesg = GetMessage(MSG_NOT_BOTH,
array(“ITEM1″=>$s_friendly1,
“ITEM2″=>$s_friendly2));
$b_ok = false;
}
}
else
{
//
// failed
//
$s_error_mesg = GetMessage(MSG_XOR,
array(“ITEM1″=>$s_friendly1,
“ITEM2″=>$s_friendly2));
$b_ok = false;
}
break;
case ‘!=’:
case ‘=’:
$b_got1 = !TestFieldEmpty($s_fld1,$a_vars,$s_empty1);
$b_got2 = !TestFieldEmpty($s_fld2,$a_vars,$s_empty2);
if ($b_got1 && $b_got2)
$b_match = (GetFieldValue($s_fld1,$a_vars) ==
GetFieldValue($s_fld2,$a_vars));
elseif (!$b_got1 && !$b_got2)
//
// haven’t got either value – they match
//
$b_match = true;
else
//
// got one value, but not the other – they don’t match
//
$b_match = false;
if ($s_oper != ‘=’)
{
//
// != operator
//
$b_match = !$b_match;
$s_desc = GetMessage(MSG_IS_SAME_AS,
array(“ITEM1″=>$s_friendly1,
“ITEM2″=>$s_friendly2));
}
else
$s_desc = GetMessage(MSG_IS_NOT_SAME_AS,
array(“ITEM1″=>$s_friendly1,
“ITEM2″=>$s_friendly2));
if (!$b_match)
{
//
// failed
//
$s_error_mesg = $s_desc;
$b_ok = false;
}
break;
}
return ($b_ok);
}

//
// Process advanced “required” conditionals
//
function AdvancedRequired($s_cond,$i_span,$a_vars,&$s_missing,&$a_missing_list)
{
$b_ok = true;
//
// get first field name
//
list($s_fld1,$s_friendly1) = GetFriendlyName(substr($s_cond,0,$i_span));
//
// get the operator
//
$s_rem = substr($s_cond,$i_span);
$i_span = strspn($s_rem,REQUIREDOPS);
$s_oper = substr($s_rem,0,$i_span);
switch ($s_oper)
{
case ‘|’:
case ‘^’:
case ‘=’:
case ‘!=’:
//
// second component is a field name
//
list($s_fld2,$s_friendly2) = GetFriendlyName(substr($s_rem,$i_span));
if (!FieldTest($s_oper,$s_fld1,$s_fld2,$a_vars,$s_error_mesg,
$s_friendly1,$s_friendly2))
{
//
// failed
//
$s_missing .= “$s_error_mesg\n”;
$a_missing_list[] = “$s_error_mesg”;
$b_ok = false;
}
break;
default:
SendAlert(GetMessage(MSG_REQD_OPER,array(“OPER”=>$s_oper)));
break;
}
return ($b_ok);
}

//
// Check the input for required values. The list of required fields
// is a comma-separated list of field names or conditionals
//
function CheckRequired($s_reqd,$a_vars,&$s_missing,&$a_missing_list)
{
$b_bad = false;
$a_list = TrimArray(explode(“,”,$s_reqd));
$s_missing = “”;
$a_missing_list = array();
for ($ii = 0 ; $ii < count($a_list) ; $ii++)
{
$s_cond = $a_list[$ii];
$i_len = strlen($s_cond);
if ($i_len <= 0)
continue;
if (($i_span = strcspn($s_cond,REQUIREDOPS)) >= $i_len)
{
//
// no advanced operator; just a field name
//
list($s_fld,$s_friendly) = GetFriendlyName($s_cond);
if (TestFieldEmpty($s_fld,$a_vars,$s_mesg))
{
if ($s_mesg === “”)
$s_mesg = “$s_friendly”;
else
$s_mesg = “$s_friendly ($s_mesg)”;
$b_bad = true;
$s_missing .= “$s_mesg\n”;
$a_missing_list[] = “$s_mesg”;
}
}
elseif (!AdvancedRequired($s_cond,$i_span,$a_vars,
$s_missing,$a_missing_list))
$b_bad = true;
}

global $REQUIRE_CAPTCHA,$SPECIAL_VALUES;

//
// implement REQUIRE_CAPTCHA feature
//
if ($REQUIRE_CAPTCHA !== “”)
{
if (!isset($SPECIAL_VALUES[“imgverify”]) || $SPECIAL_VALUES[“imgverify”] === “”)
{
$s_missing .= “$REQUIRE_CAPTCHA\n”;
$a_missing_list[] = “$REQUIRE_CAPTCHA”;
$b_bad = true;
}
}
return (!$b_bad);
}

//
// Run a condition test
//
function RunTest($s_test,$a_vars)
{
global $aAlertInfo;

$s_op_chars = “&|^!=~#<>”; // these are the characters for the operators
$i_len = strlen($s_test);
$b_ok = true;
if ($i_len <= 0)
//
// empty test – true
//
;
elseif ($s_test == “!”)
//
// test asserts false
//
$b_ok = false;
elseif (($i_span = strcspn($s_test,$s_op_chars)) >= $i_len)
//
// no operator – just check field presence
//
$b_ok = !TestFieldEmpty($s_test,$a_vars,$s_mesg);
else
{
//
// get first field name
//
$s_fld1 = trim(substr($s_test,0,$i_span));
//
// get the operator
//
$s_rem = substr($s_test,$i_span);
$i_span = strspn($s_rem,$s_op_chars);
$s_oper = substr($s_rem,0,$i_span);
switch ($s_oper)
{
case ‘&’:
case ‘|’:
case ‘^’:
case ‘=’:
case ‘!=’:
//
// get the second field name
//
$s_fld2 = trim(substr($s_rem,$i_span));
$b_ok = FieldTest($s_oper,$s_fld1,$s_fld2,$a_vars,$s_error_mesg);
break;
case ‘~’:
case ‘!~’:
//
// get the regular expression
//
$s_pat = trim(substr($s_rem,$i_span));
if (!TestFieldEmpty($s_fld1,$a_vars,$s_mesg))
$s_value = GetFieldValue($s_fld1,$a_vars);
else
$s_value = “”;
//echo “

Pattern: ‘”.htmlspecialchars($s_pat).”‘: count=”.preg_match($s_pat,$s_value).”

“;
//
// match the regular expression
//
if (preg_match($s_pat,$s_value) > 0)
$b_ok = ($s_oper == ‘~’);
else
$b_ok = ($s_oper == ‘!~’);
if (!$b_ok)
$aAlertInfo[] = GetMessage(MSG_PAT_FAILED,array(“OPER”=>$s_oper,
“PAT”=>$s_pat,
“VALUE”=>$s_value));
break;
case ‘#=’:
case ‘#!=’:
case ‘#<‘:
case ‘#>’:
case ‘#<=’:
case ‘#>=’:
//
// numeric tests
//
$s_num = trim(substr($s_rem,$i_span));
//
// if this is a file field, get the size of the file for
// numeric tests
//
if (($s_value = GetFileSize($s_fld1)) === false)
$s_value = $a_vars[$s_fld1];
if (strpos($s_num,’.’) === false)
{
//
// treat as integer
//
$m_num = (int) $s_num;
$m_fld = (int) $s_value;
}
else
{
//
// treat as floating point
//
$m_num = (float) $s_num;
$m_fld = (float) $s_value;
}
switch ($s_oper)
{
case ‘#=’:
$b_ok = ($m_fld == $m_num);
break;
case ‘#!=’:
$b_ok = ($m_fld != $m_num);
break;
case ‘#<‘:
$b_ok = ($m_fld < $m_num);
break;
case ‘#>’:
$b_ok = ($m_fld > $m_num);
break;
case ‘#<=’:
$b_ok = ($m_fld <= $m_num);
break;
case ‘#>=’:
$b_ok = ($m_fld >= $m_num);
break;
}
break;
default:
SendAlert(GetMessage(MSG_COND_OPER,array(“OPER”=>$s_oper)));
break;
}
}
return ($b_ok);
}

//
// Check the input for condition tests.
//
function CheckConditions($m_conditions,$a_vars,&$s_missing,&$a_missing_list,$m_id = false)
{
if (is_array($m_conditions))
{
//
// Sort the conditions by their numeric value. This ensures
// conditions are executed in the right order.
//
ksort($m_conditions,SORT_NUMERIC);
foreach ($m_conditions as $m_key=>$s_cond)
if (!CheckConditions($s_cond,$a_vars,$s_missing,$a_missing_list,$m_key))
return (false);
return (true);
}
$s_fld_name = “conditions”.($m_id === false ? “” : ($m_id+1));
if (!is_string($m_conditions))
{
SendAlert(GetMessage(MSG_INV_COND,array(“FLD”=>$s_fld_name)));
return (true); // pass invalid conditions
}
if ($m_conditions == “”)
return (true); // pass empty conditions
$s_cond = $m_conditions;
//
// extract the separator characters
//
if (strlen($s_cond) < 2)
{
SendAlert(GetMessage(MSG_COND_CHARS,
array(“FLD”=>$s_fld_name,”COND”=>$s_cond)));
return (true); // pass invalid conditions
}
$s_list_sep = $s_cond{0};
$s_int_sep = $s_cond{1};
$s_full_cond = $s_cond = substr($s_cond,2);
$b_bad = false;
$a_list = TrimArray(explode($s_list_sep,$s_cond));
$s_missing = “”;
$a_missing_list = array();
for ($ii = 0 ; $ii < count($a_list) ; $ii++)
{
$s_cond = $a_list[$ii];
$i_len = strlen($s_cond);
if ($i_len <= 0)
continue;
//
// split the condition into its internal components
//
$a_components = TrimArray(explode($s_int_sep,$s_cond));
if (count($a_components) < 5)
{
SendAlert(GetMessage(MSG_COND_INVALID,
array(“FLD”=>$s_fld_name,”COND”=>$s_cond,
“SEP”=>$s_int_sep)));
//
// the smallest condition has 5 components
//
continue;
}
//
// first component is ignored (it’s blank)
//
$a_components = array_slice($a_components,1);
switch ($a_components[0])
{
case “TEST”:
if (count($a_components) > 5)
{
SendAlert(GetMessage(MSG_COND_TEST_LONG,
array(“FLD”=>$s_fld_name,”COND”=>$s_cond,
“SEP”=>$s_list_sep)));
continue;
}
if (!RunTest($a_components[1],$a_vars))
{
$s_missing .= $a_components[2].”\n”;
$a_missing_list[] = $a_components[2];
$b_bad = true;
}
break;
case “IF”:
if (count($a_components) < 6)
{
SendAlert(GetMessage(MSG_COND_IF_SHORT,
array(“FLD”=>$s_fld_name,”COND”=>$s_cond,
“SEP”=>$s_int_sep)));
continue;
}
if (count($a_components) > 7)
{
SendAlert(GetMessage(MSG_COND_IF_LONG,
array(“FLD”=>$s_fld_name,”COND”=>$s_cond,
“SEP”=>$s_list_sep)));
continue;
}
if (RunTest($a_components[1],$a_vars))
$b_test = RunTest($a_components[2],$a_vars);
else
$b_test = RunTest($a_components[3],$a_vars);
if (!$b_test)
{
$s_missing .= $a_components[4].”\n”;
$a_missing_list[] = $a_components[4];
$b_bad = true;
}
break;
default:
SendAlert(GetMessage(MSG_COND_UNK,
array(“FLD”=>$s_fld_name,”COND”=>$s_cond,
“CMD”=>$a_components[0])));
break;
}
}
return (!$b_bad);
}

//
// Return a formatted list of the given environment variables.
//
function GetEnvVars($list,$s_line_feed)
{
global $VALID_ENV,$aServerVars;

$output = “”;
for ($ii = 0 ; $ii < count($list) ; $ii++)
{
$name = $list[$ii];
if ($name && array_search($name,$VALID_ENV,true) !== false)
{
//
// if the environment variable is empty or non-existent, try
// looking for the value in the server vars.
//
if (($s_value = getenv($name)) === “” || $s_value === false)
if (isset($aServerVars[$name]))
$s_value = $aServerVars[$name];
else
$s_value = “”;
$output .= $name.”=”.$s_value.$s_line_feed;
}
}
return ($output);
}
//
// open a socket connection to a filter and post the data there
//
function SocketFilter($filter,$a_filter_info,$m_data)
{
static $b_in_here = false;
global $php_errormsg;

//
// prevent recursive errors
//
if ($b_in_here)
return (““);
$b_in_here = true;

$a_errors = array();
if (!isset($a_filter_info[“site”]))
$a_errors[] = GetMessage(MSG_MISSING,array(“ITEM”=>”site”));
else
$s_site = $a_filter_info[“site”];

if (!isset($a_filter_info[“port”]))
$a_errors[] = GetMessage(MSG_MISSING,array(“ITEM”=>”port”));
else
$i_port = (int) $a_filter_info[“port”];

if (!isset($a_filter_info[“path”]))
$a_errors[] = GetMessage(MSG_MISSING,array(“ITEM”=>”path”));
else
$s_path = $a_filter_info[“path”];

if (!isset($a_filter_info[“params”]))
$a_params = array();
elseif (!is_array($a_filter_info[“params”]))
$a_errors[] = GetMessage(MSG_NEED_ARRAY,array(“ITEM”=>”params”));
else
$a_params = $a_filter_info[“params”];

if (!empty($a_errors))
{
Error(“bad_filter”,GetMessage(MSG_FILTER_WRONG,array(
“FILTER”=>$filter,
“ERRORS”=>implode(‘, ‘,$a_errors))),false,false);
exit;
}

//
// ready to build the socket – we need a longer time limit for the
// script if we’re doing this; we allow 30 seconds for the connection
// (should be instantaneous, especially if it’s the same domain)
//
set_time_limit(60);
@ $f_sock = fsockopen($s_site,$i_port,$i_errno,$s_errstr,30);
if ($f_sock === false)
{
Error(“filter_connect”,GetMessage(MSG_FILTER_CONNECT,array(
“FILTER”=>$filter,
“SITE”=>$s_site,
“ERRNUM”=>$i_errno,
“ERRSTR”=>”$s_errstr (“.CheckString($php_errormsg).”)”)),
false,false);
exit;
}
//
// build the data to send
//
$m_request_data = array();
$i_count = 0;
foreach ($a_params as $m_var)
{
$i_count++;
//
// if the parameter spec is an array, process it specially;
// it must have “name” and “file” elements
//
if (is_array($m_var))
{
if (!isset($m_var[“name”]))
{
Error(“bad_filter”,GetMessage(MSG_FILTER_PARAM,
array(“FILTER”=>$filter,
“NUM”=>$i_count,
“NAME”=>”name”)),false,false);
fclose($f_sock);
exit;
}
$s_name = $m_var[“name”];
if (!isset($m_var[“file”]))
{
Error(“bad_filter”,GetMessage(MSG_FILTER_PARAM,
array(“FILTER”=>$filter,
“NUM”=>$i_count,
“NAME”=>”file”)),false,false);
fclose($f_sock);
exit;
}
//
// open the file and read its contents
//
@ $fp = fopen($m_var[“file”],”r”);
if ($fp === false)
{
Error(“filter_error”,GetMessage(MSG_FILTER_OPEN_FILE,
array(“FILTER”=>$filter,
“FILE”=>$m_var[“file”],
“ERROR”=>CheckString($php_errormsg))),false,false);
fclose($f_sock);
exit;
}
$s_data = “”;
$n_lines = 0;
while (!feof($fp))
{
if (($s_line = fgets($fp,2048)) === false)
if (feof($fp))
break;
else
{
Error(“filter_error”,GetMessage(MSG_FILTER_FILE_ERROR,
array(“FILTER”=>$filter,
“FILE”=>$m_var[“file”],
“ERROR”=>CheckString($php_errormsg),
“NLINES”=>$n_lines)),false,false);
fclose($f_sock);
exit;
}
$s_data .= $s_line;
$n_lines++;
}

fclose($fp);
$m_request_data[] = “$s_name=”.urlencode($s_data);
}
else
$m_request_data[] = (string) $m_var;
}
//
// add the data
//
if (is_array($m_data))
$m_request_data[] = “data=”.urlencode(implode(BODY_LF,$m_data));
else
$m_request_data[] = “data=”.urlencode($m_data);
$s_request = implode(“&”,$m_request_data);

if (($i_pos = strpos($s_site,”://”)) !== false)
$s_site_name = substr($s_site,$i_pos+3);
else
$s_site_name = $s_site;

fputs($f_sock,”POST $s_path HTTP/1.0\r\n”);
fputs($f_sock,”Host: $s_site_name\r\n”);
fputs($f_sock,”Content-Type: application/x-www-form-urlencoded\r\n”);
fputs($f_sock,”Content-Length: “.strlen($s_request).”\r\n”);
fputs($f_sock,”\r\n”);
fputs($f_sock,”$s_request\r\n”);

//
// now read the response
//
$m_hdr = “”;
$m_data = “”;
$b_in_hdr = true;
$b_ok = false;
while (!feof($f_sock))
{
if (($s_line = fgets($f_sock,2048)) === false)
if (feof($f_sock))
break;
else
{
Error(“filter_failed”,GetMessage(MSG_FILTER_READ_ERROR,
array(“FILTER”=>$filter,
“ERROR”=>CheckString($php_errormsg))),false,false);
fclose($f_sock);
exit;
}
//
// look for an “__OK__” line
//
if (trim($s_line) == “__OK__”)
$b_ok = true;
elseif ($b_in_hdr)
{
//
// blank line signals end of header
//
if (trim($s_line) == “”)
$b_in_hdr = false;
else
$m_hdr .= $s_line;
}
else
$m_data .= $s_line;
}
//
// if not OK, then report error
//
if (!$b_ok)
{
Error(“filter_failed”,GetMessage(MSG_FILTER_NOT_OK,
array(“FILTER”=>$filter,
“DATA”=>$m_data)),false,false);
fclose($f_sock);
exit;
}
fclose($f_sock);
$b_in_here = false;
return ($m_data);
}

//
// run data through a supported filter
//
function Filter($filter,$m_data)
{
global $FILTERS,$SOCKET_FILTERS;
global $php_errormsg;
static $b_in_here = false;

//
// prevent recursive errors
//
if ($b_in_here)
return (““);
$b_in_here = true;

//
// Any errors sent in an alert are flagged to not run through the
// filter – this also means the user’s data won’t be included in the
// alert.
// The reason for this is that the Filter is typically an encryption
// program. If the filter fails, then sending the user’s data in
// clear text in an alert breaks the security of having encryption
// in the first place!
//

//
// find the filter
//
if (!isset($FILTERS[$filter]) || $FILTERS[$filter] == “”)
{
//
// check for SOCKET_FILTERS
//
if (!isset($SOCKET_FILTERS[$filter]) || $SOCKET_FILTERS[$filter] == “”)
{
ErrorWithIgnore(“bad_filter”,GetMessage(MSG_FILTER_UNK,
array(“FILTER”=>$filter)),false,false);
exit;
}
$m_data = SocketFilter($filter,$SOCKET_FILTERS[$filter],$m_data);
}
elseif ($FILTERS[$filter] == “null”)
//
// do nothing – just return the original data unchanged
//
;
elseif ($FILTERS[$filter] == “csv”)
$m_data = BuiltinFilterCSV();
else
{
$cmd = $FILTERS[$filter];
//
// get the program name – assumed to be the first blank-separated word
//
$a_words = preg_split(‘/\s+/’,$cmd);
$prog = $a_words[0];

$s_cwd = getcwd();
//
// change to the directory that contains the filter program
//
$dirname = dirname($prog);
if ($dirname != “” && $dirname != “.” && !chdir($dirname))
{
Error(“chdir_filter”,GetMessage(MSG_FILTER_CHDIR,
array(“DIR”=>$dirname,”FILTER”=>$filter,
“ERROR”=>CheckString($php_errormsg))),false,false);
exit;
}

//
// the output of the filter goes to a temporary file; this works
// OK on Windows too, even with the Unix shell syntax.
//
$temp_file = GetTempName(“FMF”);
$cmd = “$cmd > $temp_file 2>&1″;
//
// start the filter
//
$pipe = popen($cmd,”w”);
if ($pipe === false)
{
$s_sv_err = CheckString($php_errormsg);
$err = join(”,file($temp_file));
unlink($temp_file);
Error(“filter_not_found”,GetMessage(MSG_FILTER_NOTFOUND,
array(“CMD”=>$cmd,”FILTER”=>$filter,
“ERROR”=>$s_sv_err)),false,false,$err);
exit;
}
//
// write the data to the filter
//
if (is_array($m_data))
fwrite($pipe,implode(BODY_LF,$m_data));
else
fwrite($pipe,$m_data);
if (($i_st = pclose($pipe)) != 0)
{
$s_sv_err = CheckString($php_errormsg);
$err = join(”,file($temp_file));
unlink($temp_file);
Error(“filter_failed”,GetMessage(MSG_FILTER_ERROR,
array(“FILTER”=>$filter,
“ERROR”=>$s_sv_err,
“STATUS”=>$i_st)),false,false,$err);
exit;
}
//
// read in the filter’s output and return as the data to be sent
//
$m_data = join(”,file($temp_file));
unlink($temp_file);

//
// return to previous directory
//
chdir($s_cwd);
}
$b_in_here = false;
return ($m_data);
}

/*
* Class: CSVFormat
* Description:
* Manages formatting of CSV content.
*/
class CSVFormat
{
var $_cSep; /* field separator character */
var $_cQuote; /* field quote character */
var $_cIntSep; /* internal separator character (for lists) */
var $_sEscPolicy; /* escape processing policy */
var $_sCleanFunc; /* cleaning function for fields */

/*
* Method: CSVFormat ctor
* Parameters: $c_sep the field separator
* $c_quote the quote character to use
* $c_int_sep the internal field separator to use
* $s_esc_policy escape processing policy to use
* $s_clean_func a cleaning function
* Returns: n/a
* Description:
* Constructs the object.
*/
function CSVFormat($c_sep = ‘,’,$c_quote = ‘”‘,$c_int_sep = ‘;’,
$s_esc_policy = “backslash”,$s_clean_func = NULL)
{
$this->SetSep($c_sep);
$this->SetQuote($c_quote);
$this->SetIntSep($c_int_sep);
$this->SetEscPolicy($s_esc_policy);
$this->SetCleanFunc($s_clean_func);
}

/*
* Method: SetEscPolicy
* Parameters: $s_esc_policy a string specifying the escape processing
* policy to use
* Returns: void
* Description:
* Set the escape processing policy.
*/

function SetEscPolicy($s_esc_policy)
{
switch ($s_esc_policy)
{
default: /* should generate a warning */
case “backslash”:
$this->_sEscPolicy = “b”;
break;
case “double”:
$this->_sEscPolicy = “d”;
break;
case “strip”:
$this->_sEscPolicy = “s”;
break;
case “conv”:
$this->_sEscPolicy = “c”;
break;
}
}

/*
* Method: SetSep
* Parameters: $c_sep the separator character to use
* Returns: void
* Description:
* Set the separator character for between fields.
*/
function SetSep($c_sep)
{
$this->_cSep = $c_sep;
}

/*
* Method: SetQuote
* Parameters: $c_quote the quote character to use
* Returns: void
* Description:
* Set the quote character for quoting fields.
*/
function SetQuote($c_quote)
{
$this->_cQuote = $c_quote;
}

/*
* Method: SetIntSep
* Parameters: $c_int_sep the internal separator character to use
* Returns: void
* Description:
* Set the internal separator character for inside fields.
*/
function SetIntSep($c_int_sep)
{
$this->_cIntSep = $c_int_sep;
}

/*
* Method: SetCleanFunc
* Parameters: $s_clean_func the name of a cleaning function (can be NULL)
* Returns: void
* Description:
* Set the cleaning function for fields.
*/
function SetCleanFunc($s_clean_func)
{
$this->_sCleanFunc = $s_clean_func;
}

/*
* Method: _Escape
* Parameters: $m_value the field value; string or array of strings
* Returns: mixed the field value escaped according to the
* escape processing policy
* Description:
* Escapes a field value according to the configured requirements.
*/
function _Escape($m_value)
{
switch ($this->_sEscPolicy)
{
default: /* should generate an error */
case “b”:
/*
* ‘backslash’ escape policy: replace \ with \\ and
* ” with \”
*/
$m_value = str_replace(“\\”,”\\\\”,$m_value);
$m_value = str_replace($this->_cQuote,”\\”.$this->_cQuote,
$m_value);
break;
case “d”:
/*
* ‘double’ escape policy: replace ” with “”
* This is suitable for Microsoft apps such as Excel
* and Access. It also meets the specification of
* RFC4180, though this RFC only specified double
* quotes whereas we handle any quote character.
*/
$m_value = str_replace($this->_cQuote,
$this->_cQuote.$this->_cQuote,$m_value);
break;
case “s”:
/*
* ‘strip’ escape policy: strip quotes
*/
$m_value = str_replace($this->_cQuote,””,$m_value);
break;
case “c”:
/*
* ‘conv’ escape policy: convert quotes to the other quotes
*/
switch ($this->_cQuote)
{
case ‘”‘:
/*
* convert double quotes in the data to single quotes
*/
$m_value = str_replace(“\””,”‘”,$m_value);
break;
case ‘\”:
/*
* convert single quotes in the data to double quotes
*/
$m_value = str_replace(“‘”,”\””,$m_value);
break;
default:
/*
* otherwise, leave the data unchanged
*/
break;
}
break;
}
return ($m_value);
}

function _Format($m_value)
{
$m_value = $this->_Escape($m_value);
/*
* we handle strings and arrays of strings
*/
if (is_array($m_value))
/*
* separate the values with the internal field separator
*/
$m_value = implode($this->_cIntSep,$m_value);
return ($this->_cQuote.$m_value.$this->_cQuote);
}

/*
* Method: MakeCSVRecord
* Parameters: $a_column_list a list of column names (field names) to
* include
* $a_vars raw data array indexed by column name
* (field name).
* A data value can be a string or an array
* of strings.
* Returns: string the comma-separated value
* Description:
* Creates a single CSV record for a list of columns.
*/
function MakeCSVRecord($a_column_list,$a_vars)
{
$s_rec = “”;
$n_columns = count($a_column_list);
for ($ii = 0 ; $ii < $n_columns ; $ii++)
{
$s_col_name = $a_column_list[$ii];
/*
* if a column is specified it must be included, even if there
* is no data for it.
*/
if (isset($a_vars[$s_col_name]))
{
$m_value = $a_vars[$s_col_name];
if (isset($this->_sCleanFunc))
{
$s_func = $this->_sCleanFunc;
$m_value = $s_func($m_value);
}
}
else
$m_value = “”;

$m_value = $this->_Format($m_value);
if ($ii > 0)
/*
* prepend the separator from the second field onwards
*/
$s_rec .= $this->_cSep;
$s_rec .= $m_value;
}
return ($s_rec);
}

/*
* Method: MakeHeading
* Parameters: $a_column_list a list of column names (field names) to
* include
* Returns: string the comma-separated heading record
* Description:
* Creates a heading record for the CSV data.
*/
function MakeHeading($a_column_list)
{
$s_rec = “”;
$n_columns = count($a_column_list);
for ($ii = 0 ; $ii < $n_columns ; $ii++)
{
$s_col_name = $a_column_list[$ii];
$m_value = $this->_Format($s_col_name);
if ($ii > 0)
/*
* prepend the separator from the second field onwards
*/
$s_rec .= $this->_cSep;
$s_rec .= $m_value;
}
return ($s_rec);
}
};

/*
* Built-in filter. Generates CSV (comma separated values) content from
* the submitted fields. The special field “filter_fields” determines
* which fields to include in the CSV content.
* The following options are support in “filter_options”:
* CSVHeading if set, includes a heading line first with the field names
* CSVSep specifies a separator character instead of comma
* CSVIntSep specifies an internal separator character for lists
* CSVQuote specifies the character to use to quote each column; default
* is double quotes
* CSVEscPolicy controls the way quotes are escaped in the data. Supported
* values are: backslash (the default),double,strip
* CSVRaw if set, then the fields are recorded as raw values and
* are *not* cleaned according to FormMail’s normal field
* cleaning process.
* If the “filter_fields” field does not exist, then the “csvcolumns” field is
* used instead. If neither exist, then all fields are included along with
* a Heading line.
*/
function BuiltinFilterCSV()
{
global $aAllRawValues,$aRawDataValues,$SPECIAL_VALUES,$CSVLINE;

$b_heading = false;
$a_column_list = array();
$s_cols = $SPECIAL_VALUES[“filter_fields”];
if (!isset($s_cols) || empty($s_cols) || !is_string($s_cols))
{
$s_cols = $SPECIAL_VALUES[“csvcolumns”];
if (!isset($s_cols) || empty($s_cols) || !is_string($s_cols))
{
/*
* neither filter_fields nor csvcolumns defined – get all
* columns
*/
$s_cols = “”;
/*
* special case – include these two special fields
*/
$a_column_list = array(“email”,”realname”);
/*
* now include all the data fields
*/
$a_column_list = array_merge($a_column_list,
array_keys($aRawDataValues));
$b_heading = true;
}
}
if (empty($a_column_list))
$a_column_list = TrimArray(explode(“,”,$s_cols));

$csv_format = new CSVFormat();

/*
* get the various options and set them
*/
$m_temp = GetFilterOption(“CSVQuote”);
if (isset($m_temp))
$csv_format->SetQuote($m_temp);
$m_temp = GetFilterOption(“CSVSep”);
if (isset($m_temp))
$csv_format->SetSep($m_temp);
$m_temp = GetFilterOption(“CSVIntSep”);
if (isset($m_temp))
$csv_format->SetIntSep($m_temp);
$m_temp = GetFilterOption(“CSVEscPolicy”);
if (isset($m_temp))
$csv_format->SetEscPolicy($m_temp);
$m_temp = GetFilterOption(“CSVHeading”);
if (isset($m_temp))
$b_heading = true;

/*
* clean fields unless CSVRaw is specified
*/
$m_temp = GetFilterOption(“CSVRaw”);
if (!isset($m_temp))
$csv_format->SetCleanFunc(create_function(‘$m_value’,
‘return CleanValue($m_value,false);’));

$s_csv = $csv_format->MakeCSVRecord($a_column_list,$aAllRawValues);

if ($b_heading)
{
$s_head = $csv_format->MakeHeading($a_column_list);
/*
* return the heading and the record with $CSVLINE as record separator
*/
return ($s_head.$CSVLINE.$s_csv.$CSVLINE);
}
else
/*
* return this record with $CSVLINE appended
*/
return ($s_csv.$CSVLINE);
}

$aSubstituteErrors = array();
$aSubstituteValues = NULL;
$sSubstituteMissing = NULL;

//
// Run htmlspecialchars on every value in an array.
//
function ArrayHTMLSpecialChars($a_list)
{
$a_new = array();
foreach ($a_list as $m_key=>$m_value)
if (is_array($m_value))
$a_new[$m_key] = ArrayHTMLSpecialChars($m_value);
else
$a_new[$m_key] = htmlspecialchars($m_value);
return ($a_new);
}

//
// Worker function for SubstituteValue and SubstituteValueForPage.
// Returns the value of the matched variable name.
// Variables are searched for in the global $aSubstituteValues.
// If no such variable exists, an error is reported or the given
// replacement string is used.
// Errors are stored in the global $aSubstituteErrors.
//
function SubstituteValueWorker($a_matches,$s_repl,$b_html = true)
{
global $aSubstituteErrors,$aSubstituteValues,$SPECIAL_VALUES;

$b_insert_br = true; // option to put “
” tags before newlines in HTML templates

$s_name = $a_matches[0];
assert(strlen($s_name) > 1 && $s_name{0} == ‘$’);
$s_name = substr($s_name,1);
if (($i_len = strlen($s_name)) > 0 && $s_name{0} == ‘{‘)
{
assert($s_name{$i_len-1} == ‘}’);
$s_name = substr($s_name,1,-1);
//
// grab any processing options
//
$a_args = explode(“:”,$s_name);
$s_name = $a_args[0];
if (($n_args = count($a_args)) > 1)
{
for ($ii = 1 ; $ii < $n_args ; $ii++)
{
switch ($a_args[$ii])
{
case “nobr”:
$b_insert_br = false;
break;
}
}
}
}
$s_value = “”;
if (IsFieldSet($s_name,$aSubstituteValues) &&
!TestFieldEmpty($s_name,$aSubstituteValues,$s_mesg))
{
if (isset($aSubstituteValues[$s_name]) &&
is_array($aSubstituteValues[$s_name]))
//
// note that the separator can include HTML special chars
//
$s_value = implode($SPECIAL_VALUES[‘template_list_sep’],
$b_html ?
ArrayHTMLSpecialChars($aSubstituteValues[$s_name]) :
$aSubstituteValues[$s_name]);
else
{
$s_value = GetFieldValue($s_name,$aSubstituteValues);
if ($b_html)
$s_value = htmlspecialchars($s_value);
}
if ($b_html && $b_insert_br)
//
// Insert HTML line breaks before newlines.
//
$s_value = nl2br($s_value);
}
elseif (isset($SPECIAL_VALUES[$s_name]))
$s_value = $b_html ?
htmlspecialchars((string) $SPECIAL_VALUES[$s_name]) :
(string) $SPECIAL_VALUES[$s_name];
elseif (isset($s_repl))
//
// If a replacement value has been specified use it, and
// don’t call htmlspecialchars. This allows the use
// of HTML tags in a replacement string.
//
$s_value = $s_repl;
else
$aSubstituteErrors[] = GetMessage(MSG_FLD_NOTFOUND,array(“FIELD”=>$s_name));
return ($s_value);
}

//
// Callback function for preg_replace_callback. Returns the value
// of the matched variable name.
// Variables are searched for in the global $aSubstituteValues.
// If no such variable exists, an error is reported or an special
// replacement string is used.
// Errors are stored in the global $aSubstituteErrors.
//
function SubstituteValue($a_matches)
{
global $sSubstituteMissing;

return (SubstituteValueWorker($a_matches,$sSubstituteMissing));
}

//
// Callback function for preg_replace_callback. Returns the value
// of the matched variable name.
// Variables are searched for in the global $aSubstituteValues.
// If no such variable exists, an error is reported or an special
// replacement string is used.
// Errors are stored in the global $aSubstituteErrors.
//
function SubstituteValuePlain($a_matches)
{
global $sSubstituteMissing;

return (SubstituteValueWorker($a_matches,$sSubstituteMissing,false));
}

//
// Callback function for preg_replace_callback. Returns the value
// of the matched variable name.
// Variables are searched for in the global $aSubstituteValues.
// If no such variable exists, the empty string is substituted.
// Errors are stored in the global $aSubstituteErrors.
//
function SubstituteValueForPage($a_matches)
{
return (SubstituteValueWorker($a_matches,””));
}

//
// Process the given HTML template and fill the fields.
//
function DoProcessTemplate($s_dir,$s_url,$s_template,&$a_lines,
$a_values,$s_missing,$s_subs_func)
{
global $aSubstituteErrors,$aSubstituteValues,$sSubstituteMissing;

if (($a_template_lines = LoadTemplate($s_template,$s_dir,
$s_url,true)) === false)
return (false);

$b_ok = true;
//
// initialize the errors list
//
$aSubstituteErrors = array();
//
// initialize the values
//
$aSubstituteValues = $a_values;
$sSubstituteMissing = $s_missing;

foreach ($a_template_lines as $s_line)
{
//
// search for words in these forms:
// $word
// ${word:options}
// where word begins with an alphabetic character and
// consists of alphanumeric and underscore
//
$a_lines[] = preg_replace_callback(‘/\$[a-z][a-z0-9_]*|\$\{[a-z][a-z0-9_]*(:[^\}]*)*\}/i’,
$s_subs_func,$s_line);
}

// SendAlert(“Error count=”.count($aSubstituteErrors));
if (count($aSubstituteErrors) != 0)
{
SendAlert(GetMessage(MSG_TEMPLATE_ERRORS,array(“NAME”=>$s_template)).
implode(“\n”,$aSubstituteErrors));
$b_ok = false;
}
global $FMCTemplProc;

//
// note that it’s possible for an old version of FormMail Computation
// module to get loaded which doesn’t provide FMCTemplProc
//
if ($b_ok && ADVANCED_TEMPLATES && isset($FMCTemplProc))
{
$a_mesgs = array();
/*foreach ($a_lines as $i_lno=>$s_line)
if (strpos($s_line,”\n”) !== false)
SendAlert(“Line $i_lno has a newline”);*/
set_time_limit(60);
if (($m_result = $FMCTemplProc->Process(implode(“\n”,$a_lines),$a_mesgs)) === false)
{
$s_msgs = “\n”;
foreach ($a_mesgs as $a_msg)
{
$s_msgs .= “Line “.$a_msg[“LINE”];
$s_msgs .= “, position “.$a_msg[“CHAR”].”: “;
$s_msgs .= $a_msg[“MSG”].”\n”;
}
Error(“fmadvtemplates”,GetMessage(MSG_TEMPL_PROC,
array(“ERRORS”=>$s_msgs)),false,false);
$b_ok = false;
}
else
{
/*foreach ($m_result as $i_lno=>$s_line)
if (($nn = substr_count($s_line,”\n”)) > 1)
SendAlert(“Result line $i_lno has $nn newlines”);*/
//
// strip the new lines
//
$a_lines = explode(“\n”,implode(“”,$m_result));
}
$a_alerts = $FMCTemplProc->GetAlerts();
if (count($a_alerts) > 0)
SendAlert(GetMessage(MSG_TEMPL_ALERT,
array(“ALERTS”=>implode(“\n”,$a_alerts))));
$a_debug = $FMCTemplProc->GetDebug();
if (count($a_debug) > 0)
SendAlert(GetMessage(MSG_TEMPL_DEBUG,
array(“DEBUG”=>implode(“\n”,$a_debug))));
}

return ($b_ok);
}

//
// Process the given HTML template and fill the fields.
//
function ProcessTemplate($s_template,&$a_lines,$a_values,$s_missing = NULL,
$s_subs_func = ‘SubstituteValue’)
{
global $TEMPLATEURL,$TEMPLATEDIR;

if (empty($TEMPLATEDIR) && empty($TEMPLATEURL))
{
SendAlert(GetMessage(MSG_TEMPLATES));
return (false);
}
return (DoProcessTemplate($TEMPLATEDIR,$TEMPLATEURL,$s_template,$a_lines,
$a_values,$s_missing,$s_subs_func));
}

//
// Output the given HTML template after filling in the fields.
//
function OutputTemplate($s_template,$a_values)
{
$a_lines = array();
if (!ProcessTemplate($s_template,$a_lines,$a_values,””,’SubstituteValueForPage’))
Error(“template_failed”,GetMessage(MSG_TEMPLATE_FAILED,
array(“NAME”=>$s_template)),false,false);
else
{
for ($ii = 0 ; $ii < count($a_lines) ; $ii++)
echo $a_lines[$ii].”\n”;
}
}

//
// This function handles input type fields.
//
function RemoveFieldValue($s_name,$s_buf)
{
//
// we search for:
//
// and change it to:
//
//

// handle name attribute first
$s_pat = ‘/<(\s*input[^>]*name=”‘;
$s_pat .= preg_quote($s_name,”/”);
$s_pat .= ‘”[^>]*)>’;
$s_pat .= ‘/ims’;
$s_buf = preg_replace($s_pat,”,$s_buf);

return ($s_buf);
}

//
// This function handles input type “text” and “password”
//
function FixInputText($s_name,$s_value,$s_buf)
{
//
// we search for:
// ‘,$s_buf);

// handle name attribute first
$s_pat = ‘/(<\s*input[^>]*name=”‘;
$s_pat .= preg_quote($s_name,”/”);
$s_pat .= ‘”[^>]*type=”(?:text|password)”[^>]*)(value=”[^”]*”)([^>]*?)(\s*\/\s*)?>’;
$s_pat .= ‘/ims’;
$s_buf = preg_replace($s_pat,’$1$3$4>’,$s_buf);

//
// now add in the new value
//
$s_repl = ‘$1 value=”‘.htmlspecialchars($s_value).'” $2>’;

// handle type attribute first
$s_pat = ‘/(<\s*input[^>]*type=”(?:text|password)”[^>]*name=”‘;
$s_pat .= preg_quote($s_name,”/”);
$s_pat .= ‘”[^>]*?)(\s*\/\s*)?>’;
$s_pat .= ‘/ims’;
$s_buf = preg_replace($s_pat,$s_repl,$s_buf);

// handle name attribute first
$s_pat = ‘/(<\s*input[^>]*name=”‘;
$s_pat .= preg_quote($s_name,”/”);
$s_pat .= ‘”[^>]*type=”(?:text|password)”[^>]*?)(\s*\/\s*)?>’;
$s_pat .= ‘/ims’;
$s_buf = preg_replace($s_pat,$s_repl,$s_buf);

return ($s_buf);
}

//
// This function handles textareas.
//
function FixTextArea($s_name,$s_value,$s_buf)
{
//
// we search for:
//
// and change it to:
//
//

$s_pat = ‘/(<\s*textarea[^>]*name=”‘;
$s_pat .= preg_quote($s_name,”/”);
$s_pat .= ‘”[^>]*)>.*?<\s*\/\s*textarea\s*>’;
$s_pat .= ‘/ims’;
//
// we exclude the closing ‘>’ from the match above so that
// we can put it below. We need to do this so that the replacement
// string is not faulty if the value begins with a digit:
// $19 Some Street
//
$s_repl = ‘$1>’.htmlspecialchars($s_value).”;
$s_buf = preg_replace($s_pat,$s_repl,$s_buf);

return ($s_buf);
}

//
// This function handles radio buttons and non-array checkboxes.
//
function FixButton($s_name,$s_value,$s_buf)
{
//
// we search for:
//
// [^>]*?[^”\w] matches up to a word boundary starting with
// ‘checked’ but not ‘”checked’
// (=”checked”|(?=[^”\w]))? this matches:
// nothing
// =”checked”
// any character except a word character or ” (without
// consuming it)
//
$s_pat = ‘/(<\s*input[^>]*type=”(?:radio|checkbox)”[^>]*name=”‘;
$s_pat .= preg_quote($s_name,”/”);
$s_pat .= ‘”[^>]*?[^”\w])checked(=”checked”|(?=[^”\w]))?([^>]*?)(\s*\/\s*)?>’;
$s_pat .= ‘/ims’;
$s_buf = preg_replace($s_pat,’$1$3$4>’,$s_buf);

// handle name attribute first
$s_pat = ‘/(<\s*input[^>]*name=”‘;
$s_pat .= preg_quote($s_name,”/”);
$s_pat .= ‘”[^>]*type=”(?:radio|checkbox)”[^>]*?[^”\w])checked(=”checked”|(?=[^”\w]))?([^>]*?)(\s*\/\s*)?>’;
$s_pat .= ‘/ims’;
$s_buf = preg_replace($s_pat,’$1$3$4>’,$s_buf);

// handle type attribute first
$s_pat = ‘/(<\s*input[^>]*type=”(?:radio|checkbox)”[^>]*name=”‘;
$s_pat .= preg_quote($s_name,”/”);
$s_pat .= ‘”[^>]*value=”‘;
$s_pat .= preg_quote($s_value,”/”);
$s_pat .= ‘”)([^>]*?)(\s*\/\s*)?>’;
$s_pat .= ‘/ims’;
$s_buf = preg_replace($s_pat,’$1$2 checked=”checked” $3>’,$s_buf);

// handle name attribute first
$s_pat = ‘/(<\s*input[^>]*name=”‘;
$s_pat .= preg_quote($s_name,”/”);
$s_pat .= ‘”[^>]*type=”(?:radio|checkbox)”[^>]*value=”‘;
$s_pat .= preg_quote($s_value,”/”);
$s_pat .= ‘”)([^>]*?)(\s*\/\s*)?>’;
$s_pat .= ‘/ims’;
$s_buf = preg_replace($s_pat,’$1$2 checked=”checked” $3>’,$s_buf);

return ($s_buf);
}

//
// This function handles checkboxes as an array of values.
//
function FixCheckboxes($s_name,$a_values,$s_buf)
{
//global $aDebug;

//
// we search for:
//
$s_pat = ‘/(<\s*input[^>]*type=”checkbox”[^>]*name=”‘;
$s_pat .= preg_quote($s_name,”/”);
$s_pat .= ‘\[]”[^>]*?[^”\w])checked(=”checked”|(?=[^”\w]))?([^>]*?)(\s*\/\s*)?>’;
$s_pat .= ‘/ims’;
$s_buf = preg_replace($s_pat,’$1$3$4>’,$s_buf);

// handle name attribute first
$s_pat = ‘/(<\s*input[^>]*name=”‘;
$s_pat .= preg_quote($s_name,”/”);
$s_pat .= ‘\[]”[^>]*type=”checkbox”[^>]*?[^”\w])checked(=”checked”|(?=[^”\w]))?([^>]*?)(\s*\/\s*)?>’;
$s_pat .= ‘/ims’;
$s_buf = preg_replace($s_pat,’$1$3$4>’,$s_buf);

foreach ($a_values as $s_value)
{
// handle type attribute first
$s_pat = ‘/(<\s*input[^>]*type=”checkbox”[^>]*name=”‘;
$s_pat .= preg_quote($s_name,”/”);
$s_pat .= ‘\[\]”[^>]*value=”‘;
$s_pat .= preg_quote($s_value,”/”);
$s_pat .= ‘”)([^>]*?)(\s*\/\s*)?>’;
$s_pat .= ‘/ims’;
$s_buf = preg_replace($s_pat,’$1$2 checked=”checked”$3>’,$s_buf);
//$aDebug[] = “Name=’$s_name’, pat=’$s_pat'”;

// handle name attribute first
$s_pat = ‘/(<\s*input[^>]*name=”‘;
$s_pat .= preg_quote($s_name,”/”);
$s_pat .= ‘\[\]”[^>]*type=”checkbox”[^>]*value=”‘;
$s_pat .= preg_quote($s_value,”/”);
$s_pat .= ‘”)([^>]*?)(\s*\/\s*)?>’;
$s_pat .= ‘/ims’;
$s_buf = preg_replace($s_pat,’$1$2 checked=”checked”>’,$s_buf);
}
return ($s_buf);
}

//
// This function handles selects.
//
function FixSelect($s_name,$s_value,$s_buf)
{
//
// we search for:
//
//

$s_pat = ‘/(<\s*select[^>]*name=”‘;
$s_pat .= preg_quote($s_name,”/”);
$s_pat .= ‘”.*?<\s*option[^>]*value=”‘;
$s_pat .= preg_quote($s_value,”/”);
$s_pat .= ‘”[^>]*)>’;
$s_pat .= ‘/ims’;
$s_repl = ‘$1 selected=”selected”>’;
// echo “

pat: “.htmlspecialchars($s_pat);
$s_buf = preg_replace($s_pat,$s_repl,$s_buf);

return ($s_buf);
}

//
// This function handles multiple selects.
//
function FixMultiSelect($s_name,$a_values,$s_buf)
{
//
// we search for:
//
//

foreach ($a_values as $s_value)
{
$s_pat = ‘/(<\s*select[^>]*name=”‘;
$s_pat .= preg_quote($s_name,”/”);
$s_pat .= ‘\[\]”.*?<\s*option[^>]*value=”‘;
$s_pat .= preg_quote($s_value,”/”);
$s_pat .= ‘”[^>]*)>’;
$s_pat .= ‘/ims’;
$s_repl = ‘$1 selected=”selected”>’;
// echo “

pat: “.htmlspecialchars($s_pat);
$s_buf = preg_replace($s_pat,$s_repl,$s_buf);
}
return ($s_buf);
}

//
// This function unchecks all checkboxes and select options.
//
function UnCheckStuff($s_buf)
{
global $php_errormsg;

//
// we search for:
//
//

$s_pat = ‘/(<\s*input[^>]*type=”checkbox”[^>]*?[^”\w])checked(=”checked”|(?=[^”\w]))?([^>]*?)(\s*\/\s*)?>’;
$s_pat .= ‘/ims’;
$s_buf = preg_replace($s_pat,’$1$3$4>’,$s_buf);

//
// we search for:
//
//

$s_pat = ‘/(<\s*option[^>]*?[^”\w])selected(=”selected”|(?=[^”\w]))?([^>]*)>’;
$s_pat .= ‘/ims’;
$s_buf = preg_replace($s_pat,’$1$3>’,$s_buf);

return ($s_buf);
}

//
// Add the user agent to the url as a parameter called USER_AGENT.
// This allows dynamic web sites to know what the user’s browser is.
//
function AddUserAgent($s_url)
{
global $aServerVars;

//
// check for ? in the name
//
$b_quest = (strpos($s_url,’?’) !== false);
unset($s_agent);
if (isset($aServerVars[‘HTTP_USER_AGENT’]))
$s_agent = $aServerVars[‘HTTP_USER_AGENT’];
if (isset($s_agent))
$s_url .= ($b_quest ? ‘&’ : ‘?’).”USER_AGENT=”.urlencode($s_agent);
return ($s_url);
}

//
// Sets previous values in a form.
//
function SetPreviousValues($s_form_buf,$a_values,$a_strip = array())
{
//
// Uncheck any checkboxes and select options
//
$s_form_buf = UnCheckStuff($s_form_buf);
foreach ($a_values as $s_name=>$m_value)
{
if (is_array($m_value))
{
//
// note that if no values are selected for a field,
// then we will never get here for that field
//
$s_form_buf = FixCheckboxes($s_name,$m_value,$s_form_buf);
$s_form_buf = FixMultiSelect($s_name,$m_value,$s_form_buf);
}
else
{
//
// Fix the field if it’s an input type “text” or “password”.
//
$s_form_buf = FixInputText($s_name,$m_value,$s_form_buf);
//
// Fix the field if it’s radio button.
//
$s_form_buf = FixButton($s_name,$m_value,$s_form_buf);
//
// Fix the field if it’s a “textarea”.
//
$s_form_buf = FixTextArea($s_name,$m_value,$s_form_buf);
//
// Fix the field if it’s a “select”.
//
$s_form_buf = FixSelect($s_name,$m_value,$s_form_buf);
}
}
//
// Now strip particular field values.
//
foreach ($a_strip as $s_name)
$s_form_buf = RemoveFieldValue($s_name,$s_form_buf);
return ($s_form_buf);
}

//
// Open a URL, do value substitutions, and send to browser.
// The a_strip array provides a list of fields (usually
// hidden fields) to remove from the form (their values are
// set to empty).
//
function ProcessReturnToForm($s_url,$a_values,$a_strip = array())
{
global $aSubstituteErrors,$aSubstituteValues,$sSubstituteMissing;
global $php_errormsg;

//
// read the original form, and modify it to provide values
// for the fields
//
if (!CheckValidURL($s_url))
Error(“invalid_url”,GetMessage(MSG_RETURN_URL_INVALID,
array(“URL”=>$s_url)),false,false);

$s_form_url = AddUserAgent($s_url);
$s_error = “”;
$s_form_buf = GetURL($s_form_url,$s_error);
if ($s_form_buf === false)
Error(“invalid_url”,GetMessage(MSG_OPEN_URL,
array(“URL”=>$s_form_url,
“ERROR”=>$s_error.”: “.(isset($php_errormsg) ?
$php_errormsg : “”))),false,false);

//
// Next, we replace or set actual field values.
//
echo SetPreviousValues($s_form_buf,$a_values,$a_strip);
}

//
// To return the URL for returning to a particular multi-page form URL.
//
function GetReturnLink($s_this_script,$i_form_index)
{
if (!CheckValidURL($s_this_script))
Error(“not_valid_url”,GetMessage(MSG_RETURN_URL_INVALID,
array(“URL”=>$s_this_script)),false,false);

$a_params = array();
$a_params[] = “return=$i_form_index”;
if (isset($aServerVars[“QUERY_STRING”]))
$a_params[] = $aServerVars[“QUERY_STRING”];
$a_params[] = session_name().”=”.session_id();
return (AddURLParams($s_this_script,$a_params));
}

//
// Process a multi-page form template.
//
function ProcessMultiFormTemplate($s_template,$a_values,&$a_lines)
{
global $MULTIFORMURL,$MULTIFORMDIR,$SPECIAL_VALUES,$aSessionVars;

if (empty($MULTIFORMDIR) && empty($MULTIFORMURL))
{
SendAlert(GetMessage(MSG_MULTIFORM));
return (false);
}
//
// create the “this_form_url” field
//
$i_index = $aSessionVars[“FormIndex”];
$a_values[“this_form_url”] = $aSessionVars[“FormList”][$i_index][“URL”];
//
// get the persistent file fields
//
$a_values = GetSavedFileNames($a_values);
//$a_values[“prev_form”] = GetReturnLink($SPECIAL_VALUES[“this_form”]);
return (DoProcessTemplate($MULTIFORMDIR,$MULTIFORMURL,$s_template,$a_lines,
$a_values,””,’SubstituteValueForPage’));
}

//
// Output the multi-form template after filling in the fields.
//
function OutputMultiFormTemplate($s_template,$a_values)
{
$a_lines = array();
if (!ProcessMultiFormTemplate($s_template,$a_values,$a_lines))
Error(“multi_form_failed”,GetMessage(MSG_MULTIFORM_FAILED,
array(“NAME”=>$s_template)),false,false);
else
{
$n_lines = count($a_lines);
$s_buf = “”;
for ($ii = 0 ; $ii < $n_lines ; $ii++)
{
$s_buf .= $a_lines[$ii].”\n”;
unset($a_lines[$ii]); // free memory (hopefully)
}
unset($a_lines); // free memory (hopefully)

global $aSessionVars;

if (isset($aSessionVars[“FormKeep”]))
//
// put in any values that are being forward-remembered
//
echo SetPreviousValues($s_buf,$aSessionVars[“FormKeep”]);
else
echo $s_buf;
}
}

//
// Insert a preamble into a MIME message.
//
function MimePreamble(&$a_lines,$a_mesg = array())
{
$a_preamble = explode(“\n”,GetMessage(MSG_MIME_PREAMBLE));
foreach ($a_preamble as $s_line)
$a_lines[] = $s_line.HEAD_CRLF;

$a_lines[] = HEAD_CRLF; // blank line
$b_need_blank = false;
foreach ($a_mesg as $s_line)
{
$a_lines[] = $s_line.HEAD_CRLF;
if (!empty($s_line))
$b_need_blank = true;
}
if ($b_need_blank)
$a_lines[] = HEAD_CRLF; // blank line
}

//
// Create the HTML mail
//
function HTMLMail(&$a_lines,&$a_headers,$s_body,$s_template,$s_missing,$s_filter,
$s_boundary,$a_raw_fields,$b_no_plain)
{
$s_charset = GetMailOption(“CharSet”);
if (!isset($s_charset))
$s_charset = “ISO-8859-1”;
if ($b_no_plain)
{
$b_multi = false;
//
// don’t provide a plain text version – just the HTML
//
$a_headers[‘Content-Type’] = “text/html; charset=$s_charset”;
}
else
{
$b_multi = true;
$a_headers[‘Content-Type’] = “multipart/alternative; boundary=\”$s_boundary\””;

$a_pre_lines = explode(“\n”,GetMessage(MSG_MIME_HTML,
array(“NAME”=>$s_template)));

MimePreamble($a_lines,$a_pre_lines);

//
// first part – the text version only
//
$a_lines[] = “–$s_boundary”.HEAD_CRLF;
$a_lines[] = “Content-Type: text/plain; charset=$s_charset”.HEAD_CRLF;
$a_lines[] = HEAD_CRLF; // blank line
//
// treat the body like one line, even though it isn’t
//
$a_lines[] = $s_body;
$a_lines[] = HEAD_CRLF; // blank line
//
// second part – the HTML version
//
$a_lines[] = “–$s_boundary”.HEAD_CRLF;
$a_lines[] = “Content-Type: text/html; charset=$s_charset”.HEAD_CRLF;
$a_lines[] = HEAD_CRLF; // blank line
}

$a_html_lines = array();
if (!ProcessTemplate($s_template,$a_html_lines,$a_raw_fields,$s_missing))
return (false);

if (!empty($s_filter))
//
// treat the data like one line, even though it isn’t
//
$a_lines[] = Filter($s_filter,$a_html_lines);
else
foreach ($a_html_lines as $s_line)
$a_lines[] = $s_line;

if ($b_multi)
{
//
// end
//
$a_lines[] = “–$s_boundary–“.HEAD_CRLF;
$a_lines[] = HEAD_CRLF; // blank line
}
return (true);
}

//
// Add the contents of a file in base64 encoding.
//
function AddFile(&$a_lines,$s_file_name,$i_file_size,$b_remove = true)
{
global $php_errormsg;

@ $fp = fopen($s_file_name,”rb”);
if ($fp === false)
{
SendAlert(GetMessage(MSG_FILE_OPEN_ERROR,array(“NAME”=>$s_file_name,
“TYPE”=>”attachment”,
“ERROR”=>CheckString($php_errormsg))));
return (false);
}
//
// PHP under IIS has problems with the filesize function when
// the file is on another drive. So, we replaced a call
// to filesize with the $i_file_size parameter (this occurred
// in version 3.01).
//
$s_contents = fread($fp,$i_file_size);
//
// treat as a single line, even though it isn’t
//
$a_lines[] = chunk_split(base64_encode($s_contents));
fclose($fp);
if ($b_remove)
@unlink($s_file_name);
return (true);
}

//
// Add the contents of a string in base64 encoding.
//
function AddData(&$a_lines,$s_data)
{
//
// treat as a single line, even though it isn’t
//
$a_lines[] = chunk_split(base64_encode($s_data));
return (true);
}
//
// Check if a file is a valid uploaded file.
//
function IsUploadedFile($a_file_spec)
{
//
// $a_file_spec[“moved”] is our own internal flag to say we’ve
// saved the file
//
if (isset($a_file_spec[“moved”]) && $a_file_spec[“moved”])
return (true);
return (is_uploaded_file($a_file_spec[“tmp_name”]));
}

//
// Save an uploaded file to the repository directory.
//
function SaveFileInRepository(&$a_file_spec)
{
global $php_errormsg,$FILE_REPOSITORY;

//
// if a replacement name has been specified, use that, otherwise
// use the original name
//
if (isset($a_file_spec[“new_name”]))
$s_file_name = basename($a_file_spec[“new_name”]);
else
$s_file_name = basename($a_file_spec[“name”]);
$s_dest = $FILE_REPOSITORY.”/”.$s_file_name;

$b_ok = true;
$s_error = “”;

if (isset($a_file_spec[“saved_as”]) && !empty($a_file_spec[“saved_as”]))
$s_srce = $a_file_spec[“saved_as”];
else
$s_srce = $a_file_spec[“tmp_name”];

if (!FILE_OVERWRITE)
{
clearstatcache();
if (@file_exists($s_dest))
{
$b_ok = false;
$s_error = GetMessage(MSG_SAVE_FILE_EXISTS,array(“FILE”=>$s_dest));
}
}
if (MAX_FILE_UPLOAD_SIZE != 0 &&
$a_file_spec[“size”] > MAX_FILE_UPLOAD_SIZE*1024)
//
// this exits
//
UserError(“upload_size”,GetMessage(MSG_FILE_UPLOAD_SIZE,
array(“NAME”=>$a_file_spec[“name”],
“SIZE”=>$a_file_spec[“size”],
“MAX”=>MAX_FILE_UPLOAD_SIZE)));
if ($b_ok)
{
if (isset($a_file_spec[“saved_as”]) && !empty($a_file_spec[“saved_as”]))
{
if (!copy($s_srce,$s_dest) || !@unlink($s_srce))
$b_ok = false;
}
else
{
if (!move_uploaded_file($s_srce,$s_dest))
$b_ok = false;
}
if ($b_ok)
{
//
// Flag to say it’s been put in the repository.
//
$a_file_spec[“in_repository”] = true;
//
// Its new location
//
$a_file_spec[“saved_as”] = $s_dest;
//
// Now that the file has been saved, “is_uploaded_file”
// will return false. So, we create a flag to say it was
// valid.
//
$a_file_spec[“moved”] = true;
}
else
$s_error = $php_errormsg;
}
if (!$b_ok)
{
SendAlert(GetMessage(MSG_SAVE_FILE,array(
“FILE”=>$s_srce,
“DEST”=>$s_dest,
“ERR”=>$s_error)));
return (false);
}
//
// ignore chmod fails (other than reporting them)
//
if (FILE_MODE != 0 && !chmod($s_dest,FILE_MODE))
SendAlert(GetMessage(MSG_CHMOD,array(
“FILE”=>$s_dest,
“MODE”=>FILE_MODE,
“ERR”=>$s_error)));
return (true);
}

//
// Save all uploaded files to the repository directory.
//
function SaveAllFilesToRepository()
{
global $aFileVars,$aSessionVars;

if (!FILEUPLOADS || $FILE_REPOSITORY === “”)
//
// nothing to do
//
return (true);

foreach ($aFileVars as $m_file_key=>$a_upload)
{
//
// One customer reported:
// Possible file upload attack detected: name=” temp name=’none’
// on PHP 4.1.2 on RAQ4.
// So, we now also test for “name”.
//
if (!isset($a_upload[“tmp_name”]) || empty($a_upload[“tmp_name”]) ||
!isset($a_upload[“name”]) || empty($a_upload[“name”]))
continue;
if (isset($a_upload[“in_repository”]) && $a_upload[“in_repository”])
//
// already saved
//
continue;
if (!IsUploadedFile($a_upload))
{
SendAlert(GetMessage(MSG_FILE_UPLOAD_ATTACK,
array(“NAME”=>$a_upload[“name”],
“TEMP”=>$a_upload[“tmp_name”],
“FLD”=>$m_file_key)));
continue;
}
if (!SaveFileInRepository($aFileVars[$m_file_key]))
return (false);
//
// Now the file has been saved in the repository, make
// the field persistent through all further processing
// (e.g. all movements in a multi-page form)
//
if (!isset($aSessionVars[“FormSavedFiles”]))
$aSessionVars[“FormSavedFiles”] = array();
$aSessionVars[“FormSavedFiles”][$m_file_key] = $aFileVars[$m_file_key];
//
// don’t keep duplicate information
//
unset($aFileVars[$m_file_key]);
}
return (true);
}

//
// Delete an uploaded file from the repository directory.
// For security reasons, only the field name can be used. This
// uniquely identifies an uploaded file by this form process.
//
function DeleteFileFromRepository($s_fld)
{
global $aFileVars,$aSessionVars;

if (!FILEUPLOADS || $FILE_REPOSITORY === “”)
//
// nothing to do
//
return (false);

if (($a_upload = GetFileInfo($s_fld)) === false)
return (false);

if (isset($a_upload[“in_repository”]) && $a_upload[“in_repository”])
{
if (isset($a_upload[“saved_as”]) && !empty($a_upload[“saved_as”]))
@unlink($a_upload[“saved_as”]);
}
DeleteFileInfo($s_fld);
return (true);
}

//
// Save an uploaded file for later processing.
//
function SaveUploadedFile(&$a_file_spec,$s_prefix)
{
global $php_errormsg;

$s_dest = GetScratchPadFile($s_prefix);
if (!move_uploaded_file($a_file_spec[“tmp_name”],$s_dest))
{
SendAlert(GetMessage(MSG_SAVE_FILE,array(
“FILE”=>$a_file_spec[“tmp_name”],
“DEST”=>$s_dest,
“ERR”=>$php_errormsg)));
return (false);
}
$a_file_spec[“saved_as”] = $s_dest;
$a_file_spec[“moved”] = true;
return (true);
}

//
// Remove old files from the scratchpad directory.
//
function CleanScratchPad($s_prefix = “”)
{
global $lNow,$CLEANUP_TIME,$CLEANUP_CHANCE;
global $php_errormsg,$SCRATCH_PAD;

if (!isset($SCRATCH_PAD) || empty($SCRATCH_PAD))
//
// no scratchpad to cleanup!
//
return;
if ($CLEANUP_TIME <= 0)
//
// cleanup disabled
//
return;
//
// compute chance of cleanup
//
if ($CLEANUP_CHANCE < 100)
{
$i_rand = mt_rand(1,100);
if ($i_rand > $CLEANUP_CHANCE)
return;
}
if (($f_dir = @opendir($SCRATCH_PAD)) === false)
{
Error(“open_scratch_pad”,GetMessage(MSG_OPEN_SCRATCH_PAD,array(
“DIR”=>$SCRATCH_PAD,
“ERR”=>$php_errormsg)),false,false);
return;
}
$i_len = strlen($s_prefix);
while (($s_file = readdir($f_dir)) !== false)
{
$s_path = $SCRATCH_PAD.”/”.$s_file;
if (is_file($s_path) && ($i_len == 0 || substr($s_file,0,$i_len) == $s_prefix))
{
if (($a_stat = @stat($s_path)) !== false)
{
if (isset($a_stat[‘mtime’]))
$l_time = $a_stat[‘mtime’];
else
$l_time = $a_stat[9];
if (($lNow – $l_time) / 60 >= $CLEANUP_TIME)
@unlink($s_path);
}
}
}
closedir($f_dir);
}

//
// Save all uploaded files for later processing.
//
function SaveAllUploadedFiles(&$a_file_vars)
{
global $php_errormsg,$SCRATCH_PAD;

$s_prefix = “UPLD”;
if (!isset($SCRATCH_PAD) || empty($SCRATCH_PAD))
{
Error(“need_scratch_pad”,GetMessage(MSG_NEED_SCRATCH_PAD),false,false);
return (false);
}

//
// remove old uploaded files that have not been moved out.
//
CleanScratchPad($s_prefix);

foreach (array_keys($a_file_vars) as $m_file_key)
{
$a_upload = &$a_file_vars[$m_file_key];
//
// One customer reported:
// Possible file upload attack detected: name=” temp name=’none’
// on PHP 4.1.2 on RAQ4.
// So, we now also test for “name”.
//
if (!isset($a_upload[“tmp_name”]) || empty($a_upload[“tmp_name”]) ||
!isset($a_upload[“name”]) || empty($a_upload[“name”]))
continue;
//
// ensure we don’t move the file more than once
//
if (!isset($a_upload[“saved_as”]) || empty($a_upload[“saved_as”]))
if (!IsUploadedFile($a_upload))
SendAlert(GetMessage(MSG_FILE_UPLOAD_ATTACK,
array(“NAME”=>$a_upload[“name”],
“TEMP”=>$a_upload[“tmp_name”],
“FLD”=>$m_file_key)));
elseif (!SaveUploadedFile($a_upload,$s_prefix))
return (false);
}
return (true);
}

//
// Attach a file to the body of a MIME formatted email. $a_lines is the
// current body, and is modified to include the file.
// $a_file_spec must have the following values (just like an uploaded
// file specification):
// name the name of the file
// type the mime type
// tmp_name the name of the temporary file
// size the size of the temporary file
//
// Alternatively, you supply the following instead of tmp_name and size:
// data the data to attach
//
function AttachFile(&$a_lines,$s_att_boundary,$a_file_spec,$s_charset)
{
$a_lines[] = “–$s_att_boundary”.HEAD_CRLF;
//
// if a replacement name has been specified, use that, otherwise
// use the original name
//
if (isset($a_file_spec[“new_name”]))
$s_file_name = $a_file_spec[“new_name”];
else
$s_file_name = $a_file_spec[“name”];
$s_file_name = str_replace(‘”‘,”,$s_file_name);
$s_mime_type = $a_file_spec[“type”];
//
// The following says that the data is encoded in
// base64 and is an attachment and that once decoded the
// character set of the decoded data is $s_charset.
// (See RFC 1521 Section 5.)
//
$a_lines[] = “Content-Type: $s_mime_type; name=\”$s_file_name\”; charset=$s_charset”.HEAD_CRLF;
$a_lines[] = “Content-Transfer-Encoding: base64”.HEAD_CRLF;
$a_lines[] = “Content-Disposition: attachment; filename=\”$s_file_name\””.HEAD_CRLF;
$a_lines[] = HEAD_CRLF; // blank line
if (isset($a_file_spec[“tmp_name”]) && isset($a_file_spec[“size”]))
{
$s_srce = $a_file_spec[“tmp_name”];
//
// check if the file has been saved elsewhere
//
if (isset($a_file_spec[“saved_as”]) && !empty($a_file_spec[“saved_as”]))
$s_srce = $a_file_spec[“saved_as”];
return (AddFile($a_lines,$s_srce,$a_file_spec[“size”]));
}
if (!isset($a_file_spec[“data”]))
{
SendAlert(GetMessage(MSG_ATTACH_DATA));
return (false);
}
return (AddData($a_lines,$a_file_spec[“data”]));
}

//
// Reformat the email to be in MIME format.
// Process file attachments and and fill out any
// specified HTML template.
//
function MakeMimeMail(&$s_body,&$a_headers,$a_raw_fields,$s_template = “”,
$s_missing = NULL,$b_no_plain = false,
$s_filter = “”,$a_file_vars = array(),
$a_attach_spec = array())
{
global $FM_VERS,$aPHPVERSION;
global $SPECIAL_VALUES,$FILTER_ATTRIBS,$FILE_REPOSITORY;

$s_charset = GetMailOption(“CharSet”);
if (!isset($s_charset))
$s_charset = “ISO-8859-1”;
$b_att = $b_html = false;
$b_got_filter = (isset($s_filter) && !empty($s_filter));
if (isset($s_template) && !empty($s_template))
{
//
// need PHP 4.0.5 for the preg_replace_callback function
//
if (!IsPHPAtLeast(“4.0.5”))
{
SendAlert(GetMessage(MSG_PHP_HTML_TEMPLATES,
array(“PHPVERS”=>implode(“.”,$aPHPVERSION))));
return (false);
}
$b_html = true;
}
if (count($a_file_vars) > 0)
{
if (!IsPHPAtLeast(“4.0.3”))
{
SendAlert(GetMessage(MSG_PHP_FILE_UPLOADS,
array(“PHPVERS”=>implode(“.”,$aPHPVERSION))));
return (false);
}
if (!FILEUPLOADS)
SendAlert(GetMessage(MSG_FILE_UPLOAD));
elseif ($FILE_REPOSITORY === “”) // if storing on the server, don’t attach
foreach ($a_file_vars as $a_upload)
{
//
// One customer reported:
// Possible file upload attack detected: name=” temp name=’none’
// on PHP 4.1.2 on RAQ4.
// So, we now also test for “name”.
//
if (isset($a_upload[“tmp_name”]) && !empty($a_upload[“tmp_name”]) &&
isset($a_upload[“name”]) && !empty($a_upload[“name”]))
{
$b_att = true;
break;
}
}
}
//
// check for an internally-generated attachment
//
if (isset($a_attach_spec[“Data”]))
$b_att = true;

$s_uniq = md5($s_body);
$s_body_boundary = “BODY$s_uniq”;
$s_att_boundary = “PART$s_uniq”;
$a_headers[‘MIME-Version’] = “1.0 (produced by FormMail $FM_VERS from www.tectite.com)”;

//
// if the filter strips formatting, then we’ll only have plain text
// to send, even after the template has been used
//
if ($b_got_filter && IsFilterAttribSet($s_filter,”Strips”))
//
// no HTML if the filter strips the formatting
//
$b_html = false;
$a_new = array();
if ($b_att)
{
$a_headers[‘Content-Type’] = “multipart/mixed; boundary=\”$s_att_boundary\””;

MimePreamble($a_new);
//
// add the body of the email
//
$a_new[] = “–$s_att_boundary”.HEAD_CRLF;
if ($b_html)
{
$a_lines = $a_local_headers = array();
if (!HTMLMail($a_lines,$a_local_headers,$s_body,$s_template,
$s_missing,($b_got_filter) ? $s_filter : “”,
$s_body_boundary,$a_raw_fields,$b_no_plain))
return (false);
$a_new = array_merge($a_new,ExpandMailHeadersArray($a_local_headers));
$a_new[] = HEAD_CRLF; // blank line after header
$a_new = array_merge($a_new,$a_lines);
}
else
{
$a_new[] = “Content-Type: text/plain; charset=$s_charset”.HEAD_CRLF;
$a_new[] = HEAD_CRLF; // blank line
//
// treat the body like one line, even though it isn’t
//
$a_new[] = $s_body;
}
//
// now add the attachments or save to the $FILE_REPOSITORY
//
if (FILEUPLOADS && $FILE_REPOSITORY === “”)
foreach ($a_file_vars as $m_file_key=>$a_upload)
{
//
// One customer reported:
// Possible file upload attack detected: name=” temp name=’none’
// on PHP 4.1.2 on RAQ4.
// So, we now also test for “name”.
//
if (!isset($a_upload[“tmp_name”]) || empty($a_upload[“tmp_name”]) ||
!isset($a_upload[“name”]) || empty($a_upload[“name”]))
continue;
if (!IsUploadedFile($a_upload))
{
SendAlert(GetMessage(MSG_FILE_UPLOAD_ATTACK,
array(“NAME”=>$a_upload[“name”],
“TEMP”=>$a_upload[“tmp_name”],
“FLD”=>$m_file_key)));
continue;
}
if (MAX_FILE_UPLOAD_SIZE != 0 &&
$a_upload[“size”] > MAX_FILE_UPLOAD_SIZE*1024)
UserError(“upload_size”,GetMessage(MSG_FILE_UPLOAD_SIZE,
array(“NAME”=>$a_upload[“name”],
“SIZE”=>$a_upload[“size”],
“MAX”=>MAX_FILE_UPLOAD_SIZE)));
if (!AttachFile($a_new,$s_att_boundary,$a_upload,$s_charset))
return (false);
}
if (isset($a_attach_spec[“Data”]))
{
//
// build a specification similar to a file upload
//
$a_file_spec[“name”] = isset($a_attach_spec[“Name”]) ?
$a_attach_spec[“Name”] :
“attachment.dat”;
$a_file_spec[“type”] = isset($a_attach_spec[“MIME”]) ?
$a_attach_spec[“MIME”] :
“text/plain”;
$a_file_spec[“data”] = $a_attach_spec[“Data”];
if (!AttachFile($a_new,$s_att_boundary,$a_file_spec,
isset($a_attach_spec[“CharSet”]) ?
$a_attach_spec[“CharSet”] :
$s_charset))
return (false);
}
$a_new[] = “–$s_att_boundary–“.HEAD_CRLF; // the end
$a_new[] = HEAD_CRLF; // blank line
}
elseif ($b_html)
{
if (!HTMLMail($a_new,$a_headers,$s_body,$s_template,
$s_missing,($b_got_filter) ? $s_filter : “”,
$s_body_boundary,$a_raw_fields,$b_no_plain))
return (false);
}
else
{
$a_headers[‘Content-Type’] = “text/plain; charset=$s_charset”;
//
// treat the body like one line, even though it isn’t
//
$a_new[] = $s_body;
}

$s_body = JoinLines(BODY_LF,$a_new);
return (true);
}

//
// to make a From line for the email
//
function MakeFromLine($s_email,$s_name)
{
$s_line = “”;
if (!empty($s_email))
$s_line .= $s_email.” “;
if (!empty($s_name))
$s_line .= “(“.$s_name.”)”;
return ($s_line);
}

//
// Return two sets of plain text output: the filtered fields and the
// non-filtered fields.
//
function GetFilteredOutput($a_fld_order,$a_clean_fields,$s_filter,$a_filter_list)
{
//
// find the non-filtered fields and make unfiltered text from them
//
$a_unfiltered_list = array();
$n_flds = count($a_fld_order);
for ($ii = 0 ; $ii < $n_flds ; $ii++)
if (!in_array($a_fld_order[$ii],$a_filter_list))
$a_unfiltered_list[] = $a_fld_order[$ii];
$s_unfiltered_results = MakeFieldOutput($a_unfiltered_list,$a_clean_fields);
//
// filter the specified fields only
//
$s_filtered_results = MakeFieldOutput($a_filter_list,$a_clean_fields);
$s_filtered_results = Filter($s_filter,$s_filtered_results);
return (array($s_unfiltered_results,$s_filtered_results));
}

//
// Make a plain text email body
//
function MakePlainEmail($a_fld_order,$a_clean_fields,
$s_to,$s_cc,$s_bcc,$a_raw_fields,$s_filter,$a_filter_list)
{
global $SPECIAL_VALUES,$aPHPVERSION;

$s_unfiltered_results = $s_filtered_results = “”;
$b_got_filter = (isset($s_filter) && !empty($s_filter));
if ($b_got_filter)
if (isset($a_filter_list) && count($a_filter_list) > 0)
$b_limited_filter = true;
else
$b_limited_filter = false;
$b_used_template = false;
if (IsMailOptionSet(“PlainTemplate”))
{
//
// need PHP 4.0.5 for the preg_replace_callback function
//
if (!IsPHPAtLeast(“4.0.5”))
SendAlert(GetMessage(MSG_PHP_PLAIN_TEMPLATES,
array(“PHPVERS”=>implode(“.”,$aPHPVERSION))));
else
{
$s_template = GetMailOption(“PlainTemplate”);
if (ProcessTemplate($s_template,$a_lines,$a_raw_fields,
GetMailOption(‘TemplateMissing’),
‘SubstituteValuePlain’))
{
$b_used_template = true;
$s_unfiltered_results = implode(BODY_LF,$a_lines);
if ($b_got_filter)
{
//
// with a limited filter, the template goes unfiltered
// and the named fields get filtered
//
if ($b_limited_filter)
list($s_discard,$s_filtered_results) =
GetFilteredOutput($a_fld_order,$a_clean_fields,
$s_filter,$a_filter_list);
else
{
$s_filtered_results = Filter($s_filter,$s_unfiltered_results);
$s_unfiltered_results = “”;
}
}
}
}
}
if (!$b_used_template)
{
$res_hdr = “”;

if (IsMailOptionSet(“DupHeader”))
{
//
// write some standard mail headers
//
$res_hdr = “To: $s_to”.BODY_LF;
if (!empty($s_cc))
$res_hdr .= “Cc: $s_cc”.BODY_LF;
if (!empty($SPECIAL_VALUES[“email”]))
$res_hdr .= “From: “.MakeFromLine($SPECIAL_VALUES[“email”],
$SPECIAL_VALUES[“realname”]).BODY_LF;
$res_hdr .= BODY_LF;
if (IsMailOptionSet(“StartLine”))
$res_hdr .= “–START–“.BODY_LF; // signals the beginning of the text to filter
}

//
// put the realname and the email address at the top of the results
// (if not excluded)
//
if (!IsMailExcluded(“realname”))
{
array_unshift($a_fld_order,”realname”);
$a_clean_fields[“realname”] = $SPECIAL_VALUES[“realname”];
}
if (!IsMailExcluded(“email”))
{
array_unshift($a_fld_order,”email”);
$a_clean_fields[“email”] = $SPECIAL_VALUES[“email”];
}
if ($b_got_filter)
{
if ($b_limited_filter)
list($s_unfiltered_results,$s_filtered_results) =
GetFilteredOutput($a_fld_order,$a_clean_fields,
$s_filter,$a_filter_list);
else
{
//
// make text output and filter it (filter all fields)
//
$s_filtered_results = MakeFieldOutput($a_fld_order,$a_clean_fields);
$s_filtered_results = Filter($s_filter,$s_filtered_results);
}
}
else
{
//SendAlert(“There are “.count($a_fld_order).” fields in the order array”);
//SendAlert(“Here is the clean fields array:\r\n”.var_export($a_clean_fields,true));
$s_unfiltered_results = MakeFieldOutput($a_fld_order,$a_clean_fields);
}
$s_unfiltered_results = $res_hdr.$s_unfiltered_results;
}
$s_results = $s_unfiltered_results;
if ($b_got_filter && !empty($s_filtered_results))
{
if (!empty($s_results))
$s_results .= BODY_LF;
$s_results .= $s_filtered_results;
}
return (array($s_results,$s_unfiltered_results,$s_filtered_results));
}

//
// Return the list of fields to be filtered, FALSE if no list provided.
//
function GetFilterList()
{
global $SPECIAL_VALUES;

//
// no filter means no list of fields
//
if (!empty($SPECIAL_VALUES[“filter”]))
if (isset($SPECIAL_VALUES[“filter_fields”]) && !empty($SPECIAL_VALUES[“filter_fields”]))
return (TrimArray(explode(“,”,$SPECIAL_VALUES[“filter_fields”])));
return (false);
}

//
// send the given results to the given email addresses
//
function SendResults($a_fld_order,$a_clean_fields,$s_to,$s_cc,$s_bcc,$a_raw_fields)
{
global $SPECIAL_VALUES,$aFileVars,$FILE_REPOSITORY,$FIXED_SENDER;

//
// check for a filter and how to use it
//
$b_got_filter = (isset($SPECIAL_VALUES[“filter”]) && !empty($SPECIAL_VALUES[“filter”]));
$b_filter_attach = false;
$a_attach_spec = array();
$s_filter = “”;
$a_filter_list = array();
if ($b_got_filter)
{
$s_filter = $SPECIAL_VALUES[“filter”];
$a_filter_list = GetFilterList();
if ($a_filter_list === false)
{
//
// not a limited filter, so filter all fields
//
$b_limited_filter = false;
$a_filter_list = array();
}
else
$b_limited_filter = true;
$s_filter_attach_name = GetFilterOption(“Attach”);
if (isset($s_filter_attach_name))
if (!is_string($s_filter_attach_name) || empty($s_filter_attach_name))
SendAlert(GetMessage(MSG_ATTACH_NAME));
else
{
$b_filter_attach = true;
$a_attach_spec = array(“Name”=>$s_filter_attach_name);
if (($s_mime = GetFilterAttrib($s_filter,”MIME”)) !== false)
$a_attach_spec[“MIME”] = $s_mime;
//
// Regarding the character set…
// A filter will not generally change the character set
// of the message, however, if it does, then we
// provide that information to the MIME encoder.
// Remember: this character set specification refers
// to the data *after* the effect of the filter
// has been reversed (e.g. an encrypted message
// in UTF-8 is in UTF-8 when it is decrypted).
//
if (($s_cset = GetFilterAttrib($s_filter,”CharSet”)) !== false)
$a_attach_spec[“CharSet”] = $s_cset;
}
}

//
// check the need for MIME formatted mail
//
$b_mime_mail = (IsMailOptionSet(“HTMLTemplate”) || count($aFileVars) > 0 ||
$b_filter_attach);

//
// create the email header lines – CC, BCC, From, and Reply-To
//
$a_headers = array();
if (!empty($s_cc))
$a_headers[‘Cc’] = $s_cc;
if (!empty($SPECIAL_VALUES[“replyto”]))
{
//
// expland replyto list
//
CheckEmailAddress($SPECIAL_VALUES[“replyto”],$s_list,$s_invalid,false);
if (!empty($s_list))
$a_headers[‘Reply-To’] = $s_list;
}
//
// note that BCC is documented to not work prior to PHP 4.3
//
if (!empty($s_bcc))
{
global $aPHPVERSION;

if ($aPHPVERSION[0] < 4 || ($aPHPVERSION[0] == 4 && $aPHPVERSION[1] < 3))
SendAlert(GetMessage(MSG_PHP_BCC,
array(“PHPVERS”=>implode(“.”,$aPHPVERSION))));
$a_headers[‘Bcc’] = $s_bcc;
}
//
// create the From address
//
// Some servers won’t let you set the email address to the
// submitter of the form. Therefore, use FromAddr if it’s been
// specified to set the sender and the “From” address.
//
$s_sender = GetMailOption(“FromAddr”);
if (!isset($s_sender))
{
$s_sender = “”;
if (!empty($SPECIAL_VALUES[“email”]))
$a_headers[‘From’] = MakeFromLine($SPECIAL_VALUES[“email”],
$SPECIAL_VALUES[“realname”]);
}
elseif ($s_sender !== “”)
$s_sender = $a_headers[‘From’] = UnMangle($s_sender);

/*
* Override sender if $FIXED_SENDER is set.
*/
if ($FIXED_SENDER !== “”)
$s_sender = $FIXED_SENDER;

if ($s_sender === “”)
if (SET_SENDER_FROM_EMAIL)
$s_sender = $SPECIAL_VALUES[“email”];

//
// special case: if there is only one non-special string value, then
// format it as an email (unless an option says not to)
//
$a_keys = array_keys($a_raw_fields);
if (count($a_keys) == 1 && is_string($a_raw_fields[$a_keys[0]]) &&
!IsMailOptionSet(“AlwaysList”) && !IsMailOptionSet(“DupHeader”))
{
if (IsMailExcluded($a_keys[0]))
SendAlert(“Exclusion of single field ‘”.$a_keys[0].”‘ ignored”);
$s_value = $a_raw_fields[$a_keys[0]];
//
// replace carriage return/linefeeds with
//
$s_value = str_replace(“\r\n”,’
‘,$s_value);
//
// replace lone linefeeds with
//
$s_value = str_replace(“\n”,’
‘,$s_value);
//
// remove lone carriage returns
//
$s_value = str_replace(“\r”,””,$s_value);
//
// replace all control chars with
//
$s_value = preg_replace(‘/[[:cntrl:]]+/’,’
‘,$s_value);
//
// strip HTML (note that all the
above will now be
// replaced with BODY_LF)
//
$s_value = StripHTML($s_value,BODY_LF);

if ($b_mime_mail)
{
if ($b_got_filter)
{
//
// filter the whole value (ignore filter_fields for this
// special case) if a filter has been specified
//
$s_results = Filter($s_filter,$s_value);
if ($b_filter_attach)
{
$a_attach_spec[“Data”] = $s_results;
//
// KeepInLine keeps the filtered version inline as well
// as an attachment
//
if (!IsFilterOptionSet(“KeepInLine”))
$s_results = “”;
$s_filter = “”; // no more filtering
}
}
else
$s_results = $s_value;

//
// send this single value off to get formatted in a MIME
// email
//
if (!MakeMimeMail($s_results,$a_headers,$a_raw_fields,
GetMailOption(‘HTMLTemplate’),
GetMailOption(‘TemplateMissing’),
IsMailOptionSet(“NoPlain”),
$s_filter,$aFileVars,$a_attach_spec))
return (false);
}
elseif ($b_got_filter)
//
// filter the whole value (ignore filter_fields for this special case)
// if a filter has been specified
//
$s_results = Filter($s_filter,$s_value);
else
$s_results = $s_value;
}
else
{
if ($b_mime_mail)
{
//
// get the plain text version of the email then send it
// to get MIME formatted
//
list($s_results,$s_unfiltered_results,$s_filtered_results) =
MakePlainEmail($a_fld_order,$a_clean_fields,
$s_to,$s_cc,$s_bcc,$a_raw_fields,$s_filter,
$a_filter_list);
if ($b_filter_attach)
{
//
// attached the filtered results
//
$a_attach_spec[“Data”] = $s_filtered_results;
//
// KeepInLine keeps the filtered version inline as well
// as an attachment
//
if (!IsFilterOptionSet(“KeepInLine”))
//
// put the unfiltered results in the body of the message
//
$s_results = $s_unfiltered_results;
$s_filter = “”; // no more filtering
}
if (!MakeMimeMail($s_results,$a_headers,$a_raw_fields,
GetMailOption(‘HTMLTemplate’),
GetMailOption(‘TemplateMissing’),
IsMailOptionSet(“NoPlain”),
$s_filter,$aFileVars,$a_attach_spec))
return (false);
}
else
{
list($s_results,$s_unfiltered_results,$s_filtered_results) =
MakePlainEmail($a_fld_order,$a_clean_fields,
$s_to,$s_cc,$s_bcc,$a_raw_fields,$s_filter,
$a_filter_list);
if (!$b_got_filter && IsMailOptionSet(“CharSet”))
//
// sending plain text email, and the CharSet has been
// specified; include a header
//
$a_headers[‘Content-Type’] = “text/plain; charset=”.GetMailOption(“CharSet”);
}
}

//
// append the environment variables report
//
if (isset($SPECIAL_VALUES[“env_report”]))
{
$s_results .= BODY_LF.”==================================”.BODY_LF;
$s_results .= BODY_LF.GetEnvVars(TrimArray(explode(“,”,$SPECIAL_VALUES[“env_report”])),BODY_LF);
}
//
// now save uploaded files to the repository
//
if (FILEUPLOADS && $FILE_REPOSITORY !== “”)
if (!SaveAllFilesToRepository())
return (false);

//
// send the mail – assumes the email addresses have already been checked
//
return (SendCheckedMail($s_to,$SPECIAL_VALUES[“subject”],$s_results,
$s_sender,$a_headers));
}

//
// append an entry to a log file
//
function WriteLog($log_file)
{
global $SPECIAL_VALUES,$php_errormsg;

@ $log_fp = fopen($log_file,”a”);
if ($log_fp === false)
{
SendAlert(GetMessage(MSG_FILE_OPEN_ERROR,array(“NAME”=>$log_file,
“TYPE”=>”log”,
“ERROR”=>CheckString($php_errormsg))));
return;
}
$date = gmdate(“H:i:s d-M-y T”);
$entry = $date.”:”.$SPECIAL_VALUES[“email”].”,”.
$SPECIAL_VALUES[“realname”].”,”.$SPECIAL_VALUES[“subject”].”\n”;
fwrite($log_fp,$entry);
fclose($log_fp);
}

//
// write the data to a comma-separated-values file
//
function WriteCSVFile($s_csv_file,$a_vars)
{
global $SPECIAL_VALUES,$CSVSEP,$CSVINTSEP,$CSVQUOTE,$CSVOPEN,$CSVLINE;

//
// create an array of column values in the order specified
// in $SPECIAL_VALUES[“csvcolumns”]
//
$a_column_list = $SPECIAL_VALUES[“csvcolumns”];
if (!isset($a_column_list) || empty($a_column_list) || !is_string($a_column_list))
{
SendAlert(GetMessage(MSG_CSVCOLUMNS,array(“VALUE”=>$a_column_list)));
return;
}
if (!isset($s_csv_file) || empty($s_csv_file) || !is_string($s_csv_file))
{
SendAlert(GetMessage(MSG_CSVFILE,array(“VALUE”=>$s_csv_file)));
return;
}

@ $fp = fopen($s_csv_file,”a”.$CSVOPEN);
if ($fp === false)
{
SendAlert(GetMessage(MSG_FILE_OPEN_ERROR,array(“NAME”=>$s_csv_file,
“TYPE”=>”CSV”,
“ERROR”=>CheckString($php_errormsg))));
return;
}

//
// convert the column list to an array, trim the names too
//
$a_column_list = TrimArray(explode(“,”,$a_column_list));
$n_columns = count($a_column_list);

//
// if the file is currently empty, put the column names in the first line
//
if (filesize($s_csv_file) == 0)
{
for ($ii = 0 ; $ii < $n_columns ; $ii++)
{
fwrite($fp,$CSVQUOTE.$a_column_list[$ii].$CSVQUOTE);
if ($ii < $n_columns-1)
fwrite($fp,”$CSVSEP”);
}
fwrite($fp,$CSVLINE);
}

// $debug = “”;
// $debug .= “gpc -> “.get_magic_quotes_gpc().”\n”;
// $debug .= “runtime -> “.get_magic_quotes_runtime().”\n”;
for ($ii = 0 ; $ii < $n_columns ; $ii++)
{
$s_col_name = $a_column_list[$ii];
//
// columns can be missing from some form submission and present
// from others
//
if (isset($a_vars[$s_col_name]))
$m_value = $a_vars[$s_col_name];
else
$m_value = “”;

if (LIMITED_IMPORT)
//
// the target database doesn’t understand escapes, so
// remove various things, including newlines and truncate
//
$m_value = CleanValue($m_value,false);
else
//
// the target database does understand escapes, so
// we have to slash any slashes
//
$m_value = str_replace(“\\”,”\\\\”,$m_value);
//
// convert quotes, depending on the setting of $CSVQUOTE
//
switch ($CSVQUOTE)
{
case ‘”‘:
//
// convert double quotes in the data to single quotes
//
$m_value = str_replace(“\””,”‘”,$m_value);
break;
case ‘\”:
//
// convert single quotes in the data to double quotes
//
$m_value = str_replace(“‘”,”\””,$m_value);
break;
default:
//
// otherwise, leave the data unchanged
//
break;
}
//
// we handle arrays and strings
//
if (is_array($m_value))
//
// separate the values with the internal field separator
//
$m_value = implode(“$CSVINTSEP”,$m_value);

// $debug .= $a_column_list[$ii].” => “.$m_value.”\n”;
fwrite($fp,$CSVQUOTE.$m_value.$CSVQUOTE);
if ($ii < $n_columns-1)
fwrite($fp,”$CSVSEP”);
}
fwrite($fp,$CSVLINE);
fclose($fp);
// CreatePage($debug);
// exit;
}

function CheckConfig()
{
global $TARGET_EMAIL,$CONFIG_CHECK;

$a_mesgs = array();
if (in_array(“TARGET_EMAIL”,$CONFIG_CHECK))
{
//
// $TARGET_EMAIL values should begin with ^ and end with $
//
for ($ii = 0 ; $ii < count($TARGET_EMAIL) ; $ii++)
{
$s_pattern = $TARGET_EMAIL[$ii];
if (substr($s_pattern,0,1) != ‘^’)
$a_mesgs[] = GetMessage(MSG_TARG_EMAIL_PAT_START,
array(“PAT”=>$s_pattern));
if (substr($s_pattern,-1) != ‘$’)
$a_mesgs[] = GetMessage(MSG_TARG_EMAIL_PAT_END,
array(“PAT”=>$s_pattern));
}
}
if (count($a_mesgs) > 0)
SendAlert(GetMessage(MSG_CONFIG_WARN,
array(“MESGS”=>implode(“\n”,$a_mesgs))),false,true);
}

//
// append an entry to the Auto Responder log file
//
function WriteARLog($s_to,$s_subj,$s_info)
{
global $LOGDIR,$AUTORESPONDLOG,$aServerVars,$php_errormsg;

if (!isset($LOGDIR) || !isset($AUTORESPONDLOG) ||
empty($LOGDIR) || empty($AUTORESPONDLOG))
return;

$log_file = $LOGDIR.”/”.$AUTORESPONDLOG;
@ $log_fp = fopen($log_file,”a”);
if ($log_fp === false)
{
SendAlert(GetMessage(MSG_FILE_OPEN_ERROR,array(“NAME”=>$log_file,
“TYPE”=>”log”,
“ERROR”=>CheckString($php_errormsg))));
return;
}
$a_entry = array();
$a_entry[] = gmdate(“H:i:s d-M-y T”); // date/time in GMT
$a_entry[] = $aServerVars[‘REMOTE_ADDR’]; // remote IP address
$a_entry[] = $s_to; // target email address
$a_entry[] = $s_subj; // subject line
$a_entry[] = $s_info; // information

$s_log_entry = implode(“,”,$a_entry).”\n”;
fwrite($log_fp,$s_log_entry);
fclose($log_fp);
}

//
// Send an email response to the user.
//
function AutoRespond($s_to,$s_subj,$a_values)
{
global $aPHPVERSION,$SPECIAL_VALUES,$FROM_USER;

//
// need PHP 4.0.5 for the preg_replace_callback function
//
if (!IsPHPAtLeast(“4.0.5”))
{
SendAlert(GetMessage(MSG_PHP_AUTORESP,
array(“PHPVERS”=>implode(“.”,$aPHPVERSION))));
return (false);
}

$a_headers = array();
$s_mail_text = “”;
$s_from_addr = GetAROption(“FromAddr”);

if (!isset($s_from_addr))
{
$s_from_addr = “”;
if (isset($FROM_USER) && !empty($FROM_USER))
{
if ($FROM_USER != “NONE”)
$s_from_addr = $FROM_USER;
}
else
{
global $SERVER;

$s_from_addr = “FormMail@”.$SERVER;
}
}
else
$s_from_addr = UnMangle($s_from_addr);

if (!empty($s_from_addr))
$a_headers[‘From’] = $s_from_addr;

if (IsAROptionSet(‘PlainTemplate’))
{
$s_template = GetAROption(“PlainTemplate”);
if (!ProcessTemplate($s_template,$a_lines,$a_values,
GetAROption(‘TemplateMissing’),
‘SubstituteValuePlain’))
return (false);
$s_mail_text = implode(BODY_LF,$a_lines);
}
if (IsAROptionSet(“HTMLTemplate”))
{
if (!MakeMimeMail($s_mail_text,$a_headers,$a_values,
GetAROption(“HTMLTemplate”),
GetAROption(‘TemplateMissing’)))
return (false);
}
return (SendCheckedMail($s_to,$s_subj,$s_mail_text,$s_from_addr,$a_headers));
}

/*
* The main logic starts here….
*/

//
// First, a special case; if formmail.php is called like this:
// http://…/formmail.php?testalert=1
// it sends a test message to the default alert address with some
// information about your PHP version and the DOCUMENT_ROOT.
//
if (isset($aGetVars[“testalert”]) && $aGetVars[“testalert”] == 1)
{
function ShowServerVar($s_name)
{
global $aServerVars;

return (isset($aServerVars[$s_name]) ? $aServerVars[$s_name] : “-not set-“);
}
$sAlert = GetMessage(MSG_ALERT,
array(“LANG”=>$sLangID,
“PHPVERS”=>implode(“.”,$aPHPVERSION),
“FM_VERS”=>$FM_VERS,
“SERVER”=>(IsServerWindows() ? “Windows” : “non-Windows”),
“DOCUMENT_ROOT”=>ShowServerVar(‘DOCUMENT_ROOT’),
“SCRIPT_FILENAME”=>ShowServerVar(‘SCRIPT_FILENAME’),
“PATH_TRANSLATED”=>ShowServerVar(‘PATH_TRANSLATED’),
“REAL_DOCUMENT_ROOT”=>CheckString($REAL_DOCUMENT_ROOT),
));

if (DEF_ALERT == “”)
echo “

“.GetMessage(MSG_NO_DEF_ALERT).”

“;
elseif (SendAlert($sAlert,false,true))
echo “

“.GetMessage(MSG_TEST_SENT).”

“;
else
echo “

“.GetMessage(MSG_TEST_FAILED).”

“;
exit;
}

if (isset($aGetVars[“testlang”]) && $aGetVars[“testlang”] == 1)
{
if (!IsPHPAtLeast(“4.1.0”))
{
?>

testlang feature only works with PHP version 4.1.0 or later