Begin Support Code <--- function startTimer() { global $DEBUG_ENABLED; if($DEBUG_ENABLED == "") { return; } global $timerStart; $timerStart = time(); } function endTimer($message) { global $DEBUG_ENABLED; if($DEBUG_ENABLED == "") { return; } global $timerStart; $totalTime = time() - $timerStart; debugOut($message . ". Time = $totalTime seconds"); } // outputs a message if we are debugging, otherwise a no-op function debugOut($message) { global $DEBUG_ENABLED; if($DEBUG_ENABLED != "") { echo "
" . $message; } } // the first 2 bytes are the result code, anything that follows is a // status message. returns an instance of class Pair (see below) where // the first item is the result code and the second is the status // message function readSmtpResult($sock) { $result = ""; startTimer(); $result = fgetc($sock); $result .= fgetc($sock); $result .= fgetc($sock); endTimer("SMTP result: $result"); $smtpResult = new Pair; $smtpResult->SetFirst($result); $result = ""; // read everything in the socket's buffer so that we get the status // message and the buffer is clear for the next command startTimer(); //while(false !== ($char = fgetc($sock))) //{ // $result .= $char; //} while(true) { $metadata = stream_get_meta_data($sock); if($metadata["unread_bytes"] == 0) { break; } $char = fgetc($sock); $result .= $char; } endTimer("Result message: $result"); $smtpResult->SetSecond($result); return $smtpResult; } function sendSocket($sock, $data) { startTimer(); fwrite($sock, $data); endTimer("Finished socket send"); } // interact with a mail exchange server for the domain of the email address function doSmtp($domain, $email) { // check that the domain actually exists. if it does NOT, this is a bogus email address $ip = gethostbyname($domain); // if debugging, show what we are doing $host = gethostbyname($domain); debugOut("Contacting $domain at $ip"); // open a socket to the mail exchange server $sock = @fsockopen($domain, SMTP_PORT, $errno, $errstr, SMTP_CONNECTION_TIMEOUT); // no need to go further if it fails if(!$sock) { return new Pair(ERROR, "$errno : $errstr"); } // we can't wait forever stream_set_timeout($sock, SMTP_READ_TIMEOUT); // check that the SMTP server accepted our connection $result = readSmtpResult($sock); // if not, we cannot be sure of anything if(strcmp($result->GetFirst(), SMTP_CONNECT_OK) != 0) { debugOut("Connect failed"); $result->SetFirst(EMAIL_UNSURE); fclose($sock); return $result; } // id ourselves to the SMTP server sendSocket($sock, sprintf("HELO %s\r\n", DOMAIN_TO_USE_FOR_SMTP)); // check that the SMTP server accepted our id $result = readSmtpResult($sock); // if not, we cannot be sure of anything if(strcmp($result->GetFirst(), SMTP_GENERIC_OK) != 0) { debugOut("HELO failed"); $result->SetFirst(EMAIL_UNSURE); fclose($sock); return $result; } // start a new email from us sendSocket($sock, sprintf("MAIL FROM: <%s>\r\n", EMAIL_TO_USE_FOR_SMTP)); // check that the SMTP server accepted the email start $result = readSmtpResult($sock); // if not, we cannot be sure of anything if(strcmp($result->GetFirst(), SMTP_GENERIC_OK) != 0) { debugOut("MAIL FROM failed"); $result->SetFirst(EMAIL_UNSURE); fclose($sock); return $result; } // we finally come to the crux of the matter. tell the SMTP server // that we want to deliver the email to the address that was input sendSocket($sock, sprintf("RCPT TO: <%s>\r\n", $email)); // check that the SMTP server accepted the recipient address $result = readSmtpResult($sock); // some servers employ a catch-all so that they initially accept // an email to ANY recipient (and bounce them later). so a success // here does not detect that condition. we may report a GOOD email // address when it is not - but better safe than sorry. however, // a failure here does indicate that the recipient is not known. so // we can safely conclude that an address is BAD if(strcmp($result->GetFirst(), SMTP_GENERIC_OK) != 0) { debugOut("RCPT TO failed"); $result->SetFirst(EMAIL_BAD); fclose($sock); return $result; } // if we get here, we conclude that the email address is GOOD. so // quit the conversation with the SMTP server. no email is actually // sent sendSocket($sock, "QUIT"); fclose($sock); // all done debugOut("All looks good"); return new Pair(EMAIL_GOOD, "Email OK"); } function checkEmail($email) { // checks proper email address syntax if(!preg_match(EMAIL_REGEX, $email)) { return new Pair(EMAIL_BAD, "Does not conform to proper email address format"); } // gets domain name list($username, $domain) = explode('@', $email); // checks for if MX records in the DNS $mxhosts = array(); startTimer(); $getmxrrResult = getmxrr($domain, $mxhosts); endTimer("Got MX results"); if(!$getmxrrResult || (sizeof($mxhosts) < 1)) { debugOut("No mail exchange servers found. Using domain"); // check that the domain actually exists. we have to do a little // odd stuff here because gethostbyname() and gethostbynamel() do // not behave as documented when a host name does not resolve $ip = gethostbyname($domain); debugOut("IP is $ip"); $host = @gethostbyaddr($ip); debugOut("Host is $host"); if(false == strpos($host, $domain)) { debugOut("Domain $domain not found"); return new Pair(EMAIL_BAD, "Domain not found"); } return doSmtp($domain, $email); } $result = ""; // contact each of the mail exchange servers until we get a definitive // GOOD or BAD result foreach ($mxhosts as $host) { $result = doSmtp($host, $email); if((strcmp($result->GetFirst(), EMAIL_GOOD) == 0) || (strcmp($result->GetFirst(), EMAIL_BAD) == 0)) { return $result; } } // if we get here, the result should be UNSURE or an ERROR return $result; } class Pair { var $item1; var $item2; function Pair($itemA = "", $itemB = "") { $this->item1 = $itemA; $this->item2 = $itemB; } function GetFirst() { return $this->item1; } function GetSecond() { return $this->item2; } function SetFirst($data) { $this->item1 = $data; } function SetSecond($data) { $this->item2 = $data; } } // ---> End Support Code <--- // ---> Begin Mainline Code <--- // the following was introduced because of php changes made on the primary host // site, Mozdev where requests for the original file (ending in .php) now became // redirected to this file (ending in .php.html). In this process, the values // in the $_REQUEST array got hosed-up. if(strcmp($_SERVER['REQUEST_METHOD'], "GET") == 0) { // get the request query bits if (strpos($_SERVER["REQUEST_URI"], "?")) { $QueryString = explode("?", $_SERVER["REQUEST_URI"]); $QueryArray = explode("&", $QueryString[1]); foreach ($QueryArray as $QueryItem) { $QuerySegment = explode("=", $QueryItem, 2); $_GET[$QuerySegment[0]] = urldecode($QuerySegment[1]); } } // get input parameters $DEBUG_ENABLED = $_GET["test"]; $EMAIL_ADDRESS = $_GET["emailAddress"]; $THUNDERPLUNGER_ID = $_GET["accessKey"]; } else { $DEBUG_ENABLED = $_REQUEST["test"]; $EMAIL_ADDRESS = $_REQUEST["emailAddress"]; $THUNDERPLUNGER_ID = $_REQUEST["accessKey"]; } $timerStart; // check that we are being invoked via the thunderplunger addon if($THUNDERPLUNGER_ID != THUNDERPLUNGER_GUID) { // we ignore this if we are in test mode if($DEBUG_ENABLED != "") { debugOut("No access key provided - ignored"); } else { // otherwise, it is an error header($_SERVER['SERVER_PROTOCOL'] . " " . ERROR . " Missing or incorrect access key"); header("Status: " . ERROR . " Missing or incorrect access key", true); return; } } // invoke the email check using the input email address $checkResult = checkEmail($EMAIL_ADDRESS); // if we are debugging, output our final conclusion if($DEBUG_ENABLED != "") { if(strcmp($checkResult->GetFirst(), EMAIL_GOOD) == 0) { debugOut("good"); } else { if(strcmp($checkResult->GetFirst(), EMAIL_BAD) == 0) { debugOut("bad"); } else { debugOut("unsure"); } } debugOut($checkResult->GetSecond()); } // check for leading garbage $message = ltrim($checkResult->GetSecond(), " ~!@#$%^&*()_+=`';:=-[]{}|\<>.,?/\n"); // only take the first line of a multi-line response $message = strtok($message, "\n"); debugOut("Message is $message"); // the following header sets the function's status code and message header($_SERVER['SERVER_PROTOCOL'] . " " . $checkResult->GetFirst() . " " . $message, true, $checkResult->GetFirst()); header("Status: " . $checkResult->GetFirst() . " " . $message, true); return; // ---> End Mainline Code <--- ?>