public function applyConclusiveMatch($userAgent) { // Normalize AFNetworking and server-bag UAs // Pippo/2.4.3 (iPad; iOS 8.0.2; Scale/2.00) // server-bag [iPhone OS,8.2,12D508,iPhone4,1] // iPhone4,1/8.2 (12D508) if (preg_match('#^[^/]+?/[\\d\\.]+? \\(i[A-Za-z]+; iOS ([\\d\\.]+); Scale/[\\d\\.]+\\)#', $userAgent, $matches) || preg_match('#^server-bag \\[iPhone OS,([\\d\\.]+),#', $userAgent, $matches) || preg_match('#^i(?:Phone|Pad|Pod)\\d+?,\\d+?/([\\d\\.]+)#', $userAgent, $matches)) { $matches[1] = str_replace('.', '_', $matches[1]); if (Utils::checkIfContains($userAgent, 'iPad')) { $userAgent = 'Mozilla/5.0 (iPad; CPU OS {' . $matches[1] . '} like Mac OS X) AppleWebKit/538.39.2 (KHTML, like Gecko) Version/7.0 Mobile/12A4297e Safari/9537.53 ' . $userAgent; } elseif (Utils::checkIfContains($userAgent, 'iPod touch')) { $userAgent = 'Mozilla/5.0 (iPod touch; CPU iPhone OS {' . $matches[1] . '} like Mac OS X) AppleWebKit/538.41 (KHTML, like Gecko) Version/7.0 Mobile/12A307 Safari/9537.53 ' . $userAgent; } elseif (Utils::checkIfContains($userAgent, 'iPod')) { $userAgent = 'Mozilla/5.0 (iPod; CPU iPhone OS {' . $matches[1] . '} like Mac OS X) AppleWebKit/538.41 (KHTML, like Gecko) Version/7.0 Mobile/12A307 Safari/9537.53 ' . $userAgent; } else { $userAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS {' . $matches[1] . '} like Mac OS X) AppleWebKit/601.1.10 (KHTML, like Gecko) Version/8.0 Mobile/12E155 Safari/600.1.4 ' . $userAgent; } } // Normalize Skype SDK UAs if (preg_match('#^iOSClientSDK/\\d+\\.+[0-9\\.]+ +?\\((Mozilla.+)\\)$#', $userAgent, $matches)) { $userAgent = $matches[1]; } // Normalize iOS {Ver} style UAs //Eg: Mozilla/5.0 (iPhone; U; CPU iOS 7.1.2 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Safari/528.16 if (preg_match('#CPU iOS \\d+?\\.\\d+?#', $userAgent)) { $ua = Utils::checkIfContains($userAgent, 'iPad') ? str_replace('CPU iOS', 'CPU OS', $userAgent) : str_replace('CPU iOS', 'CPU iPhone OS', $userAgent); if (preg_match('#(CPU(?: iPhone)? OS [\\d\\.]+ like)#', $ua, $matches)) { $versionUnderscore = str_replace('.', '_', $matches[1]); $ua = str_replace(' U;', '', $ua); $ua = preg_replace('#CPU(?: iPhone)? OS ([\\d\\.]+) like#', $versionUnderscore, $ua); $userAgent = $ua; } } // Attempt to find hardware version $device_version = null; if (preg_match('#(?:iPhone|iPad|iPod) ?(\\d,\\d)#', $userAgent, $matches)) { // Check for iPod first since they contain 'iPhone' if (Utils::checkIfContains($userAgent, 'iPod')) { if (array_key_exists($matches[1], self::$ipodDeviceMap)) { $device_version = str_replace(array_keys(self::$ipodDeviceMap), array_values(self::$ipodDeviceMap), $matches[1]); } } elseif (Utils::checkIfContains($userAgent, 'iPad')) { if (array_key_exists($matches[1], self::$ipadDeviceMap)) { $device_version = str_replace(array_keys(self::$ipadDeviceMap), array_values(self::$ipadDeviceMap), $matches[1]); } } elseif (Utils::checkIfContains($userAgent, 'iPhone')) { if (array_key_exists($matches[1], self::$iphoneDeviceMap)) { $device_version = str_replace(array_keys(self::$iphoneDeviceMap), array_values(self::$iphoneDeviceMap), $matches[1]); } // Set $device_version to null if UA contains unrecognized hardware version or does not satisfy any of the above 'if' statements } else { $device_version = null; } } $tolerance = Utils::firstChar($userAgent, '_'); if ($tolerance !== false) { // The first char after the first underscore ++$tolerance; } else { $index = strpos($userAgent, 'like Mac OS X;'); if ($index !== false) { // Step through the search string to the semicolon at the end $tolerance = $index + 14; } else { // Non-typical UA, try full length match $tolerance = strlen($userAgent); } } $ris_id = $this->getDeviceIDFromRIS($userAgent, $tolerance); //Assemble and check iOS HW ID if ($device_version !== null) { $test_id = $ris_id . '_subhw' . $device_version; if (in_array($test_id, self::$constantIDs)) { return $test_id; } } return $ris_id; }