E-mail address validator and online control in PHP

Posted 9 months ago     828      php validation email

E-mail validation may be a trouble and often a simple filter or regex validation is not enough, to most common way to check if an address is correct is to send a confirmation message, with this simple class I would provide a way to validate standard address using regex and also check if the address exists without send a confirmation message and also check if provider is a trusted one or a temporary one, in order to prevent spam e-mails.
Be aware: the online validation will make some request to provider server in order to test them and a little "chat" with one of them due to checking if the account exists, for this reason it may be a bit slow.
For check trusted and temporary e-mail providers I use a simple database in SQLite format (which I'll link for download) with most known providers.

Regex source


class EMailChecker{ const CHECK_SYNTAX = 1; const CHECK_SERVER = 2; const CHECK_ACCOUNT = 3; private static $trustedDB = NULL; private static $MXTimeout = 1; private static $ProbingTimeout = 90; public static function setTrustedDBLocation($path){ self::$trustedDB = empty($path) ? NULL : $path; return self; } public static function getTrustedDBLocation(){ return self::$trustedDB; } public static function setMXTimeout($timeout){ self::$MXTimeout = intval($timeout) <= 0 ? 1 : intval($timeout); return true; } public static function getMXTimeout(){ return self::$MXTimeout; } public static function setProbingTimeout($timeout){ self::$ProbingTimeout = intval($timeout) <= 0 ? 1 : intval($timeout); return true; } public static function getProbingTimeout(){ return self::$ProbingTimeout; } public static function check($mail, $deepness = NULL){ $deepness = $deepness === NULL || intval($deepness) <= 0 || intval($deepness) > 3 ? 1 : intval($deepness); if ( !self::validateEmailString($mail) ){ return false; } if ( $deepness >= 2 ){ list($user, $domain) = explode('@', $mail); $result = dns_get_record($domain, DNS_MX); if ( $result === false ){ return false; } foreach ( $result as $key => $value ){ if ( !isset($value['target']) || empty($value['target']) ){ continue; } $buffer = fsockopen($value['target'], 25, $errorCode, $errorStr, self::$MXTimeout); if ( $buffer !== false ){ if ( $deepness == 3 ){ $connect = fsockopen($value['target'], 25, $errorCode, $errorStr, self::$ProbingTimeout); if ( $connect !== false ){ if ( mb_substr(fgets($connect), 0, 3, 'UTF-8') === '220' ){ fputs($connect, 'HELO ' . $value['target'] . "\r\n"); fgets($connect); fputs($connect, "MAIL FROM: <no-reply@mail.com>\r\n"); $from = fgets($connect); fputs($connect, 'RCPT TO: <' . str_replace(array('<', '>', "\r", "\n"), '', $mail) . ">\r\n"); $to = fgets($connect); fputs($connect, 'QUIT'); fclose($connect); if ( $from === false || mb_substr($from, 0, 3, 'UTF-8') !== '250' || $to === false || mb_substr($to, 0, 3, 'UTF-8') !== '250' ){ return false; } } } } return true; } } return false; } return true; } public static function isTrustedProvider($mail, $allowTemp = false){ if ( self::$trustedDB === NULL || !file_exists(self::$trustedDB) ){ throw new Exception('Unconfigured DB'); } if ( !self::validateEmailString($mail) ){ return false; } try{ list($user, $domain) = explode('@', $mail); $db = new SQLite3(self::$trustedDB, SQLITE3_OPEN_READONLY); $stmt = $db->prepare('SELECT COUNT(*) AS num FROM providers WHERE domain = :domain ' . ( $allowTemp !== true ? '' : ' AND temp = 0 ' ) . 'LIMIT 1;'); $stmt->bindValue(':domain', mb_strtolower($domain, 'UTF-8'), SQLITE3_TEXT); $result = $stmt->execute(); while( $row = $result->fetchArray(SQLITE3_ASSOC) ){ return $row['num'] === 1 ? true : false; } }catch(Exception $ex){ throw new Exception('Unable to complete DB transaction'); } return false; } public static function isTemporaryProvider($mail){ if ( self::$trustedDB === NULL || !file_exists(self::$trustedDB) ){ throw new Exception('Unconfigured DB'); } if ( !self::validateEmailString($mail) ){ return false; } try{ list($user, $domain) = explode('@', $mail); $db = new SQLite3(self::$trustedDB, SQLITE3_OPEN_READONLY); $stmt = $db->prepare('SELECT COUNT(*) AS num FROM providers WHERE domain = :domain AND temp = 1 LIMIT 1;'); $stmt->bindValue(':domain', mb_strtolower($domain, 'UTF-8'), SQLITE3_TEXT); $result = $stmt->execute(); while( $row = $result->fetchArray(SQLITE3_ASSOC) ){ return $row['num'] === 1 ? true : false; } }catch(Exception $ex){ throw new Exception('Unable to complete DB transaction'); } return false; } public static function validateEmailString($mail){ return empty($mail) || !preg_match('/^(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){255,})(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){65,}@)(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22))(?:\.(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-[a-z0-9]+)*\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-[a-z0-9]+)*)|(?:\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\]))$/iD', $mail) || mb_strlen($mail, 'UTF-8') > 254 ? false : true; } }

Usage examples:


EMailChecker::check('foo@bar.com', EMailChecker::CHECK_ACCOUNT); //will return false EMailChecker::isTrustedProvider('foo@gmail.com', false); //will return true EMailChecker::isTemporaryProvider('foo@gmail.com'); //will return false

Tested on Ubuntu 14.04 and OSX 10.11
Speed test average (based on previus examples):

1) 0.1397 seconds.
2) 0.0007 seconds.
3) 0.0002 seconds.

Comments

There are no comments yet.

You need to be logged in to post comments.



Welcome to Snippet Repo!

Discover, share and save useful code snippets.

Join our community over over 2,000 members! Currently a 48% acceptance rate. Apply for membership →