Here is the page that the form processes to:
<?php
require 'scfconfig.php'; // Get our config
/*
* Shouldn't have to touch anything beyond here
*/
$scriptName = "SCForm";
$version = "1.2.3";
$errors = array();
// Function, shared by the show_errors() and show_fatal() functions,
// to emit the list of problems. (Note: Does so as an HTML unnumbered
// list. Assumes caller has already done the HTML "opening" stuff.)
function show_error_list($errors) {
$nerrors = count($errors);
print("<ul>\n");
for($i = 0; $i < $nerrors; $i++)
print("<li>" . $errors[$i] . "</li>\n");
print("</ul>\n");
}
// Show list of non-fatal errors
function show_errors($errors) {
print("<html>\n<head><title>Error</title></head>\n
<body>\n<p>There were problems with your submission. Please go
back to the previous page and correct the following errors:
</p>\n");
show_error_list($errors);
print("</body>\n</html>");
}
// Show fatal error
function show_fatal($errors) {
print("<html>\n<head><title>Error</title></head>\n
<body>\n<p>There were problems with your submission.</p>\n");
show_error_list($errors);
print("This may be through no fault of your own and is probably not
immediately correctable. Please come back and try again later.
</p>\n</body>\n</html>\n");
}
// Read a line from a config file, stripping comments and blank lines
function read_file_line($fp) {
while(($inString = fgets($fp, 2048)) != false) {
$inString = rtrim(preg_replace('/\s*#.*/', '', $inString));
if(!empty($inString))
break;
}
return $inString;
}
// Function to check the referer against the list of acceptable
// refererers.
//
// If the $referers array is empty, returns true/pass by default
//
function check_referer($referers, $logOnReferer) {
global $errors, $scriptName;
$found = true; // Default to "pass"
// Check only if the array of allowed referers is non-empty...
if(count($referers)) {
$found = false;
if(!empty($_SERVER['HTTP_REFERER'])) {
list($referer) =
array_slice(explode("/", $_SERVER['HTTP_REFERER']), 2, 1);
for($x = 0; $x < count($referers); ++$x) {
if(eregi($referers[$x], $referer)) {
$found = true;
break;
}
}
}
if(!$found) {
$errors[] = "This form was used from an unauthorized server! (" .
$_SERVER['HTTP_REFERER'] . ")";
if($logOnReferer) {
error_log("[$scriptName] Illegal Referer. (" .
$_SERVER['HTTP_REFERER'] . ") ", 0);
}
}
}
return $found;
}
// Function to check an IP address match
// Handles CIDR notation in the thing to check against
// Note: Address to check against is expected to be in regexp format
// (i.e.: "."s escaped with "\"s)
function check_ip($chkAgainst, $chkAddr) {
$addrMatch = false; // Assume no match
// If the "check against" value contains a "/", it'll be an IP
// address (range) in CIDR notation.
if(ereg('/[0-9]', $chkAgainst)) {
# Break down dot.ted.qu.ad/bits of address to check against
list($addrBase, $hostBits) = explode('/', $chkAgainst);
list($w, $x, $y, $z) = explode('.', $addrBase);
# Convert to high and low address ints
$chkAgainst = ($w << 24) + ($x << 16) + ($y << 8) + $z;
$mask = $hostBits == 0? 0 : (~0 << (32 - $hostBits));
$lowLimit = $chkAgainst & $mask;
$highLimit = $chkAgainst | (~$mask & 0xffffffff);
# Convert addr to check to int
list($w, $x, $y, $z) = explode('.', $chkAddr);
$chkAddr = ($w << 24) + ($x << 16) + ($y << 8) + $z;
$addrMatch = (($chkAddr >= $lowLimit) && ($chkAddr <= $highLimit));
} else {
$addrMatch = ereg("^$chkAgainst", $chkAddr);
}
return $addrMatch;
}
// Function to check the given email address, the remote host (if
// available) and the remote IP against the ban list.
function check_banlist($logOnBan, $email) {
global $errors, $scriptName, $banListFile;
$notAllowed = false; // Default to allowed
// "whoto" to email address hash
$banList = array();
// Get the banList
if($fp = @fopen($banListFile, "r")) {
while($inString = read_file_line($fp))
$banList[] = $inString;
fclose($fp);
}
if(count($banList)) {
$emailFix = trim(strtolower($email));
$remoteHostFix = trim(strtolower($_SERVER['REMOTE_HOST']));
foreach($banList as $banned) {
$banFix = trim(strtolower(ereg_replace('\.', '\\.', $banned)));
if(strstr($banFix, "@")) { // email address?
if(ereg('^@', $banFix)) { // Any user @host?
// Expand the match expression to catch hosts and
// sub-domains
$banFix = ereg_replace('^@', '[@\\.]', $banFix);
if(($notAllowed = ereg("$banFix$", $emailFix))) {
$bannedOn = $emailFix;
break;
}
} elseif(ereg('@$', $banFix)) { // User at any host?
if(($notAllowed = ereg("^$banFix", $emailFix))) {
$bannedOn = $emailFix;
break;
}
} else { // User@host
if(($notAllowed = (strtolower($banned) == $emailFix))) {
$bannedOn = $emailFix;
break;
}
}
} elseif(preg_match('/^\d{1,3}(\\\.\d{1,3}){0,3}(\/\d{1,2})?$/',
$banFix)) {
// IP address
if($notAllowed = check_ip($banFix, $_SERVER['REMOTE_ADDR'])) {
$bannedOn = $_SERVER['REMOTE_ADDR'];
break;
}
// If the client is working through a proxy...
if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
if($notAllowed =
check_ip($banFix, $_SERVER['HTTP_X_FORWARDED_FOR']))
{
$bannedOn = $_SERVER['HTTP_X_FORWARDED_FOR'];
break;
}
}
} else { // Must be a host/domain name
if(($notAllowed = ereg("$banFix$", $remoteHostFix))) {
$bannedOn = $remoteHostFix;
break;
}
}
}
}
if($notAllowed) {
$errors[] = "Attempt from a banned email address, host or domain! ($bannedOn)";
if($logOnBan) {
error_log("[$scriptName] Banned on \"$bannedOn\"", 0);
}
}
return $notAllowed;
}
// Generate informational headers
function generate_additional_headers() {
global $scriptName, $version, $reportRemoteHost, $reportRemoteAddr,
$reportRemoteUser, $reportRemoteIdent, $reportOrigReferer;
// Who we are and our version
$addlHeaders = "X-Mailer: $scriptName v${version}\n";
// Remote host/address/user reporting?
if($reportRemoteHost && !empty($_SERVER['REMOTE_HOST']))
$addlHeaders .= "X-Remote-Host: " . $_SERVER['REMOTE_HOST'] . "\n";
if($reportRemoteAddr) {
if(!empty($_SERVER['REMOTE_ADDR']))
$addlHeaders .= "X-Remote-Addr: " . $_SERVER['REMOTE_ADDR'] . "\n";
// If the client is working through a proxy...
if(!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
$addlHeaders .= "X-Http-X-Forwarded-For: " .
$_SERVER['HTTP_X_FORWARDED_FOR'] . "\n";
}
if($reportRemoteUser && !empty($_SERVER['REMOTE_USER']))
$addlHeaders .= "X-Remote-User: " . $_SERVER['REMOTE_USER'] . "\n";
if($reportRemoteIdent && !empty($_SERVER['REMOTE_IDENT']))
$addlHeaders .= "X-Remote-Ident: " . $_SERVER['REMOTE_IDENT'] . "\n";
if($reportOrigReferer && !empty($_POST['orig_referer']))
$addlHeaders .= "X-SCForm-Referer: " . $_POST['orig_referer'] . "\n";
return $addlHeaders;
}
// Mail advisory to $errorsTo list
function mail_advisory($errors) {
global $errorsTo, $addSubjSig;
if(!empty($errorsTo)) {
if($addSubjSig)
$finalSubject = "[$dfltSubj] ";
$finalSubject .= "Problem with form processing";
$content = "The following problem(s) occurred with contact form processing:\n\n";
$nerrors = count($errors);
for($i = 0; $i < $nerrors; $i++)
$content .= " . " . $errors[$i] . "\n";
$addlHeaders = generate_additional_headers();
// MS-Win mail servers want crlf and *don't* want a trailing pair
// Note: This code in two places! (The alternatives would've been
// just as ugly, IMO.)
if(PHP_OS == "WIN32" || PHP_OS == "WINNT") {
// It seems we only need do this with the "additional headers,"
// but we're set up here to easily add other mail() variables.
foreach (array('addlHeaders') as $foo) {
$$foo = preg_replace("/\n$/", "", $$foo);
$$foo = preg_replace("/\n/", "\r\n", $$foo);
}
}
mail($errorsTo, $finalSubject, $content, $addlHeaders);
}
}