/** * Tests to see if: * - see if this is a debug request with appropriately formed pid, else * - see if this browser reports being a spider, doesn't support JS or doesn't support cookies * - see if the cookie for the per user test has been set so we can record the results and add to the session * - see if a session has already been opened for the request browser, if so send the info back, else * - see if detector can find an already created profile for the browser, if so send the info back, else * - see if the cookie for the full test has been set so we can build the profile, if so build the profile & send the info back, else * - start the process for building a profile for this unknown browser * * Logic is based heavily on modernizr-server * * @return {Object} an object that contains all the properties for this particular user agent */ public static function build() { // configure detector from config.ini self::configure(); // populate some variables specific to build() $uaFileCore = __DIR__ . "/" . self::$uaDirCore . self::uaDir() . "ua." . self::$uaHash . ".json"; $uaFileExtended = __DIR__ . "/" . self::$uaDirExtended . self::uaDir() . "ua." . self::$uaHash . ".json"; $ccFile = __DIR__ . "/" . self::$uaDirCore . self::uaDir() . "cc." . self::$uaHash . ".json"; $ccFailure = __DIR__ . "/" . self::$uaDirCore . "cc-failures/cc." . self::$uaHash . "." . time() . ".json"; $uaTemplateCore = __DIR__ . "/" . self::$uaDirCore . "ua.template.json"; $uaTemplateExtended = __DIR__ . "/" . self::$uaDirExtended . "ua.template.json"; $ccTemplate = __DIR__ . "/" . self::$uaDirCore . "cc.template.json"; $pid = isset($_REQUEST['pid']) && preg_match("/[a-z0-9]{32}/", $_REQUEST['pid']) ? $_REQUEST['pid'] : false; // offer the ability to review profiles saved in the system if ($pid && self::$debug) { // where did we find this info to display... probably only need this for the demo self::$foundIn = "archive"; // decode the core data $uaJSONCore = json_decode(@file_get_contents(__DIR__ . "/" . self::$uaDirCore . self::uaDir($pid) . "ua." . $pid . ".json")); // find and decode the extended data $uaJSONExtended = json_decode(@file_get_contents(__DIR__ . "/" . self::$uaDirExtended . self::uaDir($pid) . "ua." . $pid . ".json")); // merge the data $mergedInfo = $uaJSONExtended ? (object) array_merge((array) $uaJSONCore, (array) $uaJSONExtended) : $uaJSONCore; // some general properties $mergedInfo->nojs = false; $mergedInfo->nocookies = false; // put the merged JSON info into session if (isset($_SESSION)) { $_SESSION[self::$sessionID] = $mergedInfo; } // return to the script return $mergedInfo; } else { if (self::checkSpider() || isset($_REQUEST["nojs"]) && $_REQUEST["nojs"] == "true" || isset($_REQUEST["nocookies"]) && $_REQUEST["nocookies"] == "true") { // where did we find this info to display... probably only need this for the demo self::$foundIn = "nojs"; // open the JSON template core & extended files that will be populated $jsonTemplateCore = self::openUAFile($uaTemplateCore); $jsonTemplateExtended = self::openUAFile($uaTemplateExtended); // use ua-parser-php to set-up the basic properties for this UA, populate other core properties // include the basic properties of the UA $jsonTemplateCore->ua = self::$ua; $jsonTemplateCore->uaHash = self::$uaHash; $jsonTemplateCore->coreVersion = self::$coreVersion; $jsonTemplateCore = self::createUAProperties($jsonTemplateCore); // populate extended properties $jsonTemplateExtended = !isset($jsonTemplateExtended) ? new stdClass() : $jsonTemplateExtended; $jsonTemplateExtended->ua = self::$ua; $jsonTemplateExtended->uaHash = self::$uaHash; $jsonTemplateExtended->extendedVersion = self::$extendedVersion; $mergedInfo = new stdClass(); $mergedInfo = (object) array_merge((array) $jsonTemplateCore, (array) $jsonTemplateExtended); // some general properties $mergedInfo->nojs = false; $mergedInfo->nocookies = false; // add an attribute to the object in case no js or no cookies was sent if (isset($_REQUEST["nojs"]) && $_REQUEST["nojs"] == "true") { $mergedInfo->nojs = true; } else { if (isset($_REQUEST["nocookies"]) && $_REQUEST["nocookies"] == "true") { $mergedInfo->nocookies = true; } } // try setting the session unless cookies are actively not supported if (!(isset($_REQUEST["nocookies"]) && $_REQUEST["nocookies"] == "true") && isset($_SESSION)) { $_SESSION[self::$sessionID] = $mergedInfo; } // return the collected data to the script for use in this go around return $mergedInfo; } else { if (@session_start() && isset($_SESSION) && isset($_SESSION[self::$sessionID]) && isset($_COOKIE) && isset($_COOKIE[self::$cookieID . "-ps"])) { // where did we find this info to display... probably only need this for the demo self::$foundIn = "persession"; // parse the per request cookie $cookiePerSession = new stdClass(); $cookiePerSession = self::parseCookie("ps", $cookiePerSession, true); // parse the per request cookie $cookiePerRequest = new stdClass(); $cookiePerRequest = self::parseCookie("pr", $cookiePerRequest, true); // merge the session info we already have and the info from the cookie $mergedInfo = isset($cookiePerSession) ? (object) array_merge((array) $_SESSION[self::$sessionID], (array) $cookiePerSession) : $_SESSION[self::$sessionID]; $mergedInfo = isset($cookiePerRequest) ? (object) array_merge((array) $mergedInfo, (array) $cookiePerRequest) : $mergedInfo; // unset the cookies setcookie(self::$cookieID, ""); setcookie(self::$cookieID . "-ps", ""); // put the merged JSON info into session if (isset($_SESSION)) { $_SESSION[self::$sessionID] = $mergedInfo; } // send the data back to the script to be used return $mergedInfo; } else { if (@session_start() && isset($_SESSION) && isset($_SESSION[self::$sessionID])) { // where did we find this info to display... probably only need this for the demo self::$foundIn = "session"; // parse the per request cookie $cookiePerRequest = new stdClass(); $cookiePerRequest = self::parseCookie("pr", $cookiePerRequest); // merge the session info we already have and the info from the cookie $mergedInfo = isset($cookiePerRequest) ? (object) array_merge((array) $_SESSION[self::$sessionID], (array) $cookiePerRequest) : $_SESSION[self::$sessionID]; // put the merged JSON info into session if (isset($_SESSION)) { $_SESSION[self::$sessionID] = $mergedInfo; } // send the data back to the script to be used return $mergedInfo; } else { if (($uaJSONCore = json_decode(@file_get_contents($uaFileCore))) && ($uaJSONExtended = json_decode(@file_get_contents($uaFileExtended))) && isset($_SESSION) && !isset($_SESSION[self::$sessionID . "-cc"]) && !isset($_SESSION[self::$sessionID . "-b"])) { // where did we find this info to display... probably only need this for the demo self::$foundIn = "file"; // see if we should randomly re-test this UA or if the core/extended versions have changes if ($uaJSONCore->coreVersion != self::$coreVersion || $uaJSONExtended->extendedVersion != self::$extendedVersion) { self::buildTestPage(); } else { if (rand(1, self::$ccRandomRange) == 1) { $_SESSION[self::$sessionID . "-cc"] = true; self::buildTestPage(); } } // merge the data $mergedInfo = $uaJSONExtended ? (object) array_merge((array) $uaJSONCore, (array) $uaJSONExtended) : $uaJSONCore; // some general properties $mergedInfo->nojs = false; $mergedInfo->nocookies = false; // put the merged JSON info into session if (isset($_SESSION)) { $_SESSION[self::$sessionID] = $mergedInfo; } // need to build the tests for the per user if (self::readDirFiles(self::$uaFeaturesPerSession, true)) { self::persession(); } // return to the script return $mergedInfo; } else { if (isset($_COOKIE) && isset($_COOKIE[self::$cookieID])) { // to be clear, this section means that a UA was unknown, was profiled with modernizr & now we're saving that data to build a new profile // where did we find this info to display... probably only need this for the demo self::$foundIn = "cookie"; // open the JSON template core & extended files that will be populated $jsonTemplateCore = self::openUAFile($uaTemplateCore); $jsonTemplateExtended = self::openUAFile($uaTemplateExtended); // use ua-parser-php to set-up the basic properties for this UA, populate other core properties $jsonTemplateCore->ua = self::$ua; $jsonTemplateCore->uaHash = self::$uaHash; $jsonTemplateCore->coreVersion = self::$coreVersion; $jsonTemplateCore = self::createUAProperties($jsonTemplateCore); // populate extended properties $jsonTemplateExtended = !isset($jsonTemplateExtended) ? new stdClass() : $jsonTemplateExtended; $jsonTemplateExtended->ua = self::$ua; $jsonTemplateExtended->uaHash = self::$uaHash; $jsonTemplateExtended->extendedVersion = self::$extendedVersion; // create objects to hold any of the per user or per request data. it shouldn't be saved to file but it should be added to the session $cookiePerSession = new stdClass(); $cookiePerRequest = new stdClass(); // push features into the same level as the general device information // change 1/0 to true/false. why? 'cause that's what i like to read ;) $jsonTemplateCore = self::parseCookie("core", $jsonTemplateCore, true); $jsonTemplateExtended = self::parseCookie("extended", $jsonTemplateExtended, true); $cookiePerSession = self::parseCookie("ps", $cookiePerSession, true); $cookiePerRequest = self::parseCookie("pr", $cookiePerRequest, true); // merge the data for future requests $mergedInfo = new stdClass(); $mergedInfo = $jsonTemplateExtended ? (object) array_merge((array) $jsonTemplateCore, (array) $jsonTemplateExtended) : $jsonTemplateCore; $mergedInfo = $cookiePerSession ? (object) array_merge((array) $mergedInfo, (array) $cookiePerSession) : $mergedInfo; $mergedInfo = $cookiePerRequest ? (object) array_merge((array) $mergedInfo, (array) $cookiePerRequest) : $mergedInfo; // some general properties $mergedInfo->nojs = false; $mergedInfo->nocookies = false; // write out to disk for future requests that might have the same UA $jsonTemplateCore = json_encode($jsonTemplateCore); $jsonTemplateExtended = json_encode($jsonTemplateExtended); if (@session_start() && isset($_SESSION) && isset($_SESSION['confidenceCheck']) && $_SESSION['confidenceCheck'] == true) { self::confidenceCheck($jsonTemplateCore, $ccFile, $ccFailure); } else { self::writeUAFile($jsonTemplateCore, $uaFileCore); self::writeUAFile($jsonTemplateExtended, $uaFileExtended); self::writeCCFile(md5($jsonTemplateCore), $ccTemplate, $ccFile); } // add the user agent & hash to a list of already saved user agents // this isn't really useful for anything beyond detector.dmolsen.com // self::addToUAList(); // unset the cookie that held the vast amount of test data setcookie(self::$cookieID, "", time() - 3600); unset($jsonTemplateCore); unset($jsonTemplateExtended); unset($cookiePerSession); unset($cookiePerRequest); unset($_SESSION[self::$sessionID . "-b"]); // add our collected data to the session for use in future requests, also add the per request data if (isset($_SESSION)) { $_SESSION[self::$sessionID] = $mergedInfo; } // return the collected data to the script for use in this go around return $mergedInfo; } else { // didn't recognize that the user had been here before nor the UA string. self::buildTestPage(); } } } } } } }