: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @return boolean If there were CloudFront headers to be set
public function setCfHeaders($cfHeaders = null) {
// use global _SERVER if $cfHeaders aren't defined
if (!is_array($cfHeaders) || !count($cfHeaders)) {
// clear existing headers
$this->cloudfrontHeaders = array();
// Only save CLOUDFRONT headers. In PHP land, that means only _SERVER vars that
// start with cloudfront-.
foreach ($cfHeaders as $key => $value) {
if (substr(strtolower($key), 0, 16) === 'http_cloudfront_') {
$this->cloudfrontHeaders[strtoupper($key)] = $value;
* Retrieves the cloudfront headers.
public function getCfHeaders()
return $this->cloudfrontHeaders;
* @param string $userAgent
private function prepareUserAgent($userAgent) {
$userAgent = trim($userAgent);
$userAgent = substr($userAgent, 0, 500);
* Set the User-Agent to be used.
* @param string $userAgent The user agent string to set.
public function setUserAgent($userAgent = null)
// Invalidate cache due to #375
if (false === empty($userAgent)) {
return $this->userAgent = $this->prepareUserAgent($userAgent);
foreach ($this->getUaHttpHeaders() as $altHeader) {
if (false === empty($this->httpHeaders[$altHeader])) { // @todo: should use getHttpHeader(), but it would be slow. (Serban)
$this->userAgent .= $this->httpHeaders[$altHeader] . " ";
if (!empty($this->userAgent)) {
return $this->userAgent = $this->prepareUserAgent($this->userAgent);
if (count($this->getCfHeaders()) > 0) {
return $this->userAgent = 'Amazon CloudFront';
return $this->userAgent = null;
* Retrieve the User-Agent.
* @return string|null The user agent if it's set.
public function getUserAgent()
* Set the detection type. Must be one of self::DETECTION_TYPE_MOBILE or
* self::DETECTION_TYPE_EXTENDED. Otherwise, nothing is set.
* @deprecated since version 2.6.9
* @param string $type The type. Must be a self::DETECTION_TYPE_* constant. The default
* parameter is null which will default to self::DETECTION_TYPE_MOBILE.
public function setDetectionType($type = null)
$type = self::DETECTION_TYPE_MOBILE;
if ($type !== self::DETECTION_TYPE_MOBILE && $type !== self::DETECTION_TYPE_EXTENDED) {
$this->detectionType = $type;
public function getMatchingRegex()
return $this->matchingRegex;
public function getMatchesArray()
return $this->matchesArray;
* Retrieve the list of known phone devices.
* @return array List of phone devices.
public static function getPhoneDevices()
return self::$phoneDevices;
* Retrieve the list of known tablet devices.
* @return array List of tablet devices.
public static function getTabletDevices()
return self::$tabletDevices;
* Alias for getBrowsers() method.
* @return array List of user agents.
public static function getUserAgents()
return self::getBrowsers();
* Retrieve the list of known browsers. Specifically, the user agents.
* @return array List of browsers / user agents.
public static function getBrowsers()
* Retrieve the list of known utilities.
* @return array List of utilities.
public static function getUtilities()
* Method gets the mobile detection rules. This method is used for the magic methods $detect->is*().
* @deprecated since version 2.6.9
* @return array All the rules (but not extended).
public static function getMobileDetectionRules()
* Method gets the mobile detection rules + utilities.
* The reason this is separate is because utilities rules
* don't necessary imply mobile. This method is used inside
* the new $detect->is('stuff') method.
* @deprecated since version 2.6.9
* @return array All the rules + extended.
public function getMobileDetectionRulesExtended()
// Merge all rules together.
* Retrieve the current set of rules.
* @deprecated since version 2.6.9
public function getRules()
if ($this->detectionType == self::DETECTION_TYPE_EXTENDED) {
return self::getMobileDetectionRulesExtended();
return self::getMobileDetectionRules();
* Retrieve the list of mobile operating systems.
* @return array The list of mobile operating systems.
public static function getOperatingSystems()
return self::$operatingSystems;
* Check the HTTP headers for signs of mobile.
* This is the fastest mobile check possible; it's used
* inside isMobile() method.
public function checkHttpHeadersForMobile()
foreach ($this->getMobileHeaders() as $mobileHeader => $matchType) {
if (isset($this->httpHeaders[$mobileHeader])) {
if (isset($matchType['matches']) && is_array($matchType['matches'])) {
foreach ($matchType['matches'] as $_match) {
if (strpos($this->httpHeaders[$mobileHeader], $_match) !== false) {
* Magic overloading method.
* @method boolean is[...]()
* @param array $arguments
* @throws BadMethodCallException when the method doesn't exist and doesn't start with 'is'
public function __call($name, $arguments)
// make sure the name starts with 'is', otherwise
if (substr($name, 0, 2) !== 'is') {
throw new BadMethodCallException("No such method exists: $name");
$this->setDetectionType(self::DETECTION_TYPE_MOBILE);
return $this->matchUAAgainstKey($key);
* Find a detection rule that matches the current User-agent.
* @param null $userAgent deprecated
protected function matchDetectionRulesAgainstUA($userAgent = null)
foreach ($this->getRules() as $_regex) {
if ($this->match($_regex, $userAgent)) {
* Search for a certain key in the rules array.
* If the key is found then try to match the corresponding
* regex against the User-Agent.
protected function matchUAAgainstKey($key)
// Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc.
if (false === isset($this->cache[$key])) {
// change the keys to lower case
$_rules = array_change_key_case($this->getRules());
if (false === empty($_rules[$key])) {
$this->cache[$key] = $this->match($_rules[$key]);
if (false === isset($this->cache[$key])) {
$this->cache[$key] = false;
return $this->cache[$key];
* Check if the device is mobile.
* Returns true if any type of mobile device detected, including special ones
* @param null $userAgent deprecated
* @param null $httpHeaders deprecated
public function isMobile($userAgent = null, $httpHeaders = null)
$this->setHttpHeaders($httpHeaders);
$this->setUserAgent($userAgent);
// Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
if ($this->getUserAgent() === 'Amazon CloudFront') {
$cfHeaders = $this->getCfHeaders();
if(array_key_exists('HTTP_CLOUDFRONT_IS_MOBILE_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_MOBILE_VIEWER'] === 'true') {
$this->setDetectionType(self::DETECTION_TYPE_MOBILE);
if ($this->checkHttpHeadersForMobile()) {
return $this->matchDetectionRulesAgainstUA();
* Check if the device is a tablet.
* Return true if any type of tablet device is detected.
* @param string $userAgent deprecated
* @param array $httpHeaders deprecated
public function isTablet($userAgent = null, $httpHeaders = null)
// Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
if ($this->getUserAgent() === 'Amazon CloudFront') {
$cfHeaders = $this->getCfHeaders();
if(array_key_exists('HTTP_CLOUDFRONT_IS_TABLET_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_TABLET_VIEWER'] === 'true') {
$this->setDetectionType(self::DETECTION_TYPE_MOBILE);
foreach (self::$tabletDevices as $_regex) {
if ($this->match($_regex, $userAgent)) {
* This method checks for a certain property in the
* @todo: The httpHeaders part is not yet used.
* @param string $userAgent deprecated
* @param string $httpHeaders deprecated
public function is($key, $userAgent = null, $httpHeaders = null)
// Set the UA and HTTP headers only if needed (eg. batch mode).
$this->setHttpHeaders($httpHeaders);
$this->setUserAgent($userAgent);
$this->setDetectionType(self::DETECTION_TYPE_EXTENDED);
return $this->matchUAAgainstKey($key);
* Some detection rules are relative (not standard),
* because of the diversity of devices, vendors and
* their conventions in representing the User-Agent or
* This method will be used to check custom regexes against
* @param string $userAgent
* @todo: search in the HTTP headers too.
public function match($regex, $userAgent = null)
if (!\is_string($userAgent) && !\is_string($this->userAgent)) {
$match = (bool) preg_match(sprintf('#%s#is', $regex), (false === empty($userAgent) ? $userAgent : $this->userAgent), $matches);
// If positive match is found, store the results for debug.
$this->matchingRegex = $regex;
$this->matchesArray = $matches;
* Get the properties array.
public static function getProperties()
return self::$properties;
* Prepare the version number.
* @todo Remove the error supression from str_replace() call.
* @param string $ver The string version, like "2.6.21.2152";
public function prepareVersionNo($ver)
$ver = str_replace(array('_', ' ', '/'), '.', $ver);
$arrVer = explode('.', $ver, 2);
$arrVer[1] = @str_replace('.', '', $arrVer[1]); // @todo: treat strings versions.