3v4l.org

run code in 200+ php & hhvm versions
Bugs & Features
<?php class Callcenter_Flagcustomer_Model_Observer { /** * Possibly flag an address. * * Matching an existing flagged address is an inexact science. We want * to catch most trivial circumventions but we don't want to incorrectly * flag good orders - the latter we care about MUCH more than the former. * * At the end of the day, I decided to do a basic normalized levenshtein * comparison, and if there are more than 3 total mistakes between the * flagged address and the incoming address, we flag the order. Region * and Country are exact matches due to not being input by hand. * * @param array[string] $a1 * @param array[string] $a2 * @return boolean */ public static function shouldFlag($a1, $a2) { if ($a1['region'] !== $a2['region']) { return false; } elseif ($a1['country'] !== $a2['country']) { return false; } $score = 0; $score += self::sCompare($a1['street'], $a2['street']); $score += self::compare($a1['city'], $a2['city']); $score += self::pCompare($a1['postcode'], $a2['postcode'], $a1['country'], $a2['country']); if ($score > 3) { return false; } return true; } /** * Compare two normalized strings via levenshtein distance. * * @param string $s1 String to compare. * @param string $s2 String to compare against. * @return float Score. */ private static function compare($s1, $s2) { $sn1 = self::normalize($s1); $sn2 = self::normalize($s2); $score = levenshtein($sn1, $sn2); return $score; } /** * Compare two normalized postcodes via levenshtein distance. * * @param string $s1 String to compare. * @param string $s2 String to compare against. * @param string $c1 Country of $s1. * @param string $c2 Country of $s2. * @return float Score. */ private static function pCompare($s1, $s2, $c1, $c2) { $sn1 = self::normalize($s1); $sn2 = self::normalize($s2); if (strtoupper($c1) === 'US' && strlen($sn1) === 9) { $sn1 = substr($sn1, 0, 5); } if (strtoupper($c2) === 'US' && strlen($sn2) === 9) { $sn2 = substr($sn2, 0, 5); } $score = levenshtein($sn1, $sn2); return $score; } /** * Compare two normalized street names via levenshtein distance. * * @param string $s1 String to compare. * @param string $s2 String to compare against. * @return float Score. */ private static function sCompare($s1, $s2) { $sn1 = self::sNormalize($s1); $sn2 = self::sNormalize($s2); $score = levenshtein($sn1, $sn2); return $score; } /** * Normalize a string for comparison. * * @param string $s String to normalize. * @return string */ private static function normalize($s) { // Normalize to lowercase alphanumeric. $s = strtolower(preg_replace('/[^a-zA-Z0-9]+/', '', $s)); return trim($s); } /** * Normalize an address for comparison. Has a few more steps that * are specific to addresses. * * @param string $s String to normalize. * @return string */ private static function sNormalize($s) { static $mappings = [ 'apt' => 'apartment', 'ave' => 'avenue', 'blvd' => 'boulevard', 'ct' => 'court', 'dr' => 'drive', 'e' => 'east', 'n' => 'north', 'ne' => 'northeast', 'nw' => 'northwest', 'pkwy' => 'parkway', 'pl' => 'place', 'rd' => 'road', 's' => 'south', 'se' => 'southeast', 'st' => 'street', 'sw' => 'southwest', 'w' => 'west', ]; $from = []; $to = []; foreach ($mappings as $key => $value) { $from[] = ' '.$key.' '; $to[] = ' '.$value. ' '; } // Normalize to lowercase alphanumeric with spaces. $s = strtolower(preg_replace('/[^a-zA-Z0-9 ]+/', '', $s)); // Ensure surrounded with spaces. $s = ' '.$s.' '; // Get rid of multiple spaces - turn into single spaces. $s = preg_replace('/\s{2,}/', ' ', $s); // Get rid of ordinal indicators. $s = preg_replace('/(\d+)(?:st|nd|rd|th)/', '\1', $s); // Replace street abbreviations. $s = str_replace($from, $to, $s); return trim($s); } } $result = Callcenter_Flagcustomer_Model_Observer::shouldFlag([ 'street' => '65 JANIS RD', 'city' => 'WESTFIELD', 'region' => 'MA', 'postcode' => '01085-4016', 'country' => 'US', ], [ 'street' => '65 JANIS RD', 'city' => 'WESTFIELD', 'region' => 'MA', 'postcode' => '01085-4016', 'country' => 'US', ]); var_dump($result);
Output for 5.6.30, hhvm-3.15.4 - 3.22.0, 7.0.0 - 7.2.11
bool(true)