Version 4.0.13.1
This commit is contained in:
1 parent
f9e857d255
commit
c6a86f0d9b
7517 files changed
+597400
-668041
No files matched your search
@@ -0,0 +1,341 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief User-Agent Management Class
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 20 Aug 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\Http;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* User-Agent Management Class
|
||||
*/
|
||||
class _Useragent
|
||||
{
|
||||
/**
|
||||
* @brief Search engine spider?
|
||||
*/
|
||||
public $spider = FALSE;
|
||||
|
||||
/**
|
||||
* @brief Mobile or tablet device?
|
||||
*/
|
||||
public $mobile = FALSE;
|
||||
|
||||
/**
|
||||
* @brief Browser or user agent key
|
||||
*/
|
||||
public $useragentKey = NULL;
|
||||
|
||||
/**
|
||||
* @brief Browser version
|
||||
*/
|
||||
public $useragentVersion = NULL;
|
||||
|
||||
/**
|
||||
* @brief Full user agent string
|
||||
*/
|
||||
public $useragent = NULL;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $userAgent The user agent string
|
||||
* @return void
|
||||
*/
|
||||
protected function __construct( $userAgent )
|
||||
{
|
||||
$this->useragent = $userAgent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $userAgent The user agent to parse (defaults to $_SERVER['HTTP_USER_AGENT'] if none supplied)
|
||||
* @return \IPS\Http\Useragent
|
||||
*/
|
||||
public static function parse( $userAgent=NULL )
|
||||
{
|
||||
$userAgent = $userAgent ?: ( ( isset( $_SERVER['HTTP_USER_AGENT'] ) ) ? $_SERVER['HTTP_USER_AGENT'] : '' );
|
||||
|
||||
$obj = new static( $userAgent );
|
||||
$obj->parseUserAgent();
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Human-Readable Browser Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
if ( \IPS\Member::loggedIn()->language()->checkKeyExists( 'useragent-' . $this->useragentKey ) )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->get( 'useragent-' . $this->useragentKey ) . ( $this->useragentVersion ? " {$this->useragentVersion}" : '' );
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->useragentKey;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the user agent data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function parseUserAgent()
|
||||
{
|
||||
/* Is this a spider? */
|
||||
foreach( array_merge( $this->searchEngineUseragents, $this->mobileEngineUseragents, $this->standardEngineUseragents ) as $key => $regex )
|
||||
{
|
||||
if( is_array( $regex ) )
|
||||
{
|
||||
foreach( $regex as $_expression )
|
||||
{
|
||||
if( preg_match( "#" . $_expression . "#im", $this->useragent, $matches ) )
|
||||
{
|
||||
$this->useragentKey = $key;
|
||||
|
||||
if( isset( $matches[1] ) AND !empty( $matches[1] ) )
|
||||
{
|
||||
$this->useragentVersion = $matches[1];
|
||||
}
|
||||
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( preg_match( "#" . $regex . "#im", $this->useragent, $matches ) )
|
||||
{
|
||||
$this->useragentKey = $key;
|
||||
|
||||
if( isset( $matches[1] ) AND !empty( $matches[1] ) )
|
||||
{
|
||||
$this->useragentVersion = $matches[1];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set mobile/spider flag as appropriate */
|
||||
if( $this->useragentKey )
|
||||
{
|
||||
if( array_key_exists( $this->useragentKey, $this->searchEngineUseragents ) )
|
||||
{
|
||||
$this->spider = TRUE;
|
||||
}
|
||||
else if( array_key_exists( $this->useragentKey, $this->mobileEngineUseragents ) )
|
||||
{
|
||||
$this->mobile = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->useragentKey = 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief List of search engine user agent strings with regex to parse out the data.
|
||||
* @note Matches will be checked based on the order of this list - put more specific matches first and more generic matches later
|
||||
* @note If you wish to capture a version, be sure to have just ONE capturing parenthesis group (i.e. $matches[1])
|
||||
* @note You may put multiple regex definitions for a single key into an array
|
||||
* @note If the UA matches an entry in this array, $this->spider will be set to TRUE
|
||||
*/
|
||||
protected $searchEngineUseragents = array(
|
||||
'about' => "Libby[_/ ]([0-9.]{1,10})",
|
||||
'adsense' => array( "Mediapartners-Google/([0-9.]{1,10})", "Mediapartners-Google" ),
|
||||
'ahrefs' => "AhrefsBot",
|
||||
'alexa' => "^ia_archive",
|
||||
'altavista' => "Scooter[ /\-]*[a-z]*([0-9.]{1,10})",
|
||||
'ask' => "Ask[ \-]?Jeeves",
|
||||
'baidu' => "^baiduspider\-",
|
||||
'bing' => array( "bingbot[ /]([0-9.]{1,10})", "msnbot(?:-media)?[ /]([0-9.]{1,10})" ),
|
||||
'brandwatch' => "magpie-crawler",
|
||||
'excite' => "Architext[ \-]?Spider",
|
||||
'google' => array( "Googl(?:e|ebot)(?:-Image|-Video|-News)?/([0-9.]{1,10})", "Googl(?:e|ebot)(?:-Image|-Video|-News)?/?" ),
|
||||
'googlemobile' => array( "Googl(?:e|ebot)(?:-Mobile)?/([0-9.]{1,10})", "Googl(?:e|ebot)(?:-Mobile)?/" ),
|
||||
'facebook' => "facebookexternalhit/([0-9.]{1,10})",
|
||||
'infoseek' => array( "SideWinder[ /]?([0-9a-z.]{1,10})", "Infoseek" ),
|
||||
'inktomi' => "slurp@inktomi\.com",
|
||||
'internetseer' => "^InternetSeer\.com",
|
||||
'look' => "www\.look\.com",
|
||||
'looksmart' => "looksmart-sv-fw",
|
||||
'lycos' => "Lycos_Spider_",
|
||||
'majestic' => "MJ12bot\/v([0-9.]{1,10})",
|
||||
'msproxy' => "MSProxy[ /]([0-9.]{1,10})",
|
||||
'webcrawl' => "webcrawl\.net",
|
||||
'websense' => "(?:Sqworm|websense|Konqueror/3\.(?:0|1)(?:\-rc[1-6])?; i686 Linux; 2002[0-9]{4})",
|
||||
'yahoo' => "Yahoo(?:.*?)(?:Slurp|FeedSeeker)",
|
||||
'yandex' => "Yandex(?:[^\/]+?)\/([0-9.]{1,10})",
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief List of mobile device user agent strings with regex to parse out the data.
|
||||
* @note Matches will be checked based on the order of this list - put more specific matches first and more generic matches later
|
||||
* @note If you wish to capture a version, be sure to have just ONE capturing parenthesis group (i.e. $matches[1])
|
||||
* @note You may put multiple regex definitions for a single key into an array
|
||||
* @note If the UA matches an entry in this array, $this->mobile will be set to TRUE
|
||||
*/
|
||||
protected $mobileEngineUseragents = array(
|
||||
'transformer' => ";\s+?Transformer\s+?",
|
||||
'android' => "\sandroid\s+?([A-Za-z0-9.]{1,10}).+?mobile",
|
||||
'firefoxmobile' => "Mozilla(?:[^\(]+?)\((?:android|tablet)",
|
||||
'androidtablet' => "\sandroid\s+?([A-Za-z0-9.]{1,10})",
|
||||
'blackberry' => "blackberry\s?(\d+?)[\/;]",
|
||||
'iphone' => "iphone;",
|
||||
'ipodtouch' => "ipod;",
|
||||
'iPad' => "iPad;",
|
||||
'sonyericsson' => "^SonyEricsson[A-Za-z0-9]",
|
||||
'nokia' => "Nokia[A-Za-z0-9]",
|
||||
'motorola' => "^mot-[A-Za-z0-9]",
|
||||
'samsung' => "^samsung-[A-Za-z0-9]",
|
||||
'siemens' => "^sie-[A-Za-z0-9]",
|
||||
'htc' => "(?:htc-|htc_)([A-Za-z0-9.]{1,10})",
|
||||
'lg' => "^(?:lg|lge)-[A-Za-z0-9]",
|
||||
'palm' => "(?:palmsource/| pre/[0-9.]{1,10}|palm webos)",
|
||||
'operamini' => "opera (?:mobi|mini)",
|
||||
'windows7' => "Windows Phone OS ([^;]+);",
|
||||
'windows8' => "Windows Phone ([^;]+);",
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief List of other user agent strings (desktop browsers) with regex to parse out the data.
|
||||
* @note Matches will be checked based on the order of this list - put more specific matches first and more generic matches later
|
||||
* @note If you wish to capture a version, be sure to have just ONE capturing parenthesis group (i.e. $matches[1])
|
||||
* @note You may put multiple regex definitions for a single key into an array
|
||||
*/
|
||||
protected $standardEngineUseragents = array(
|
||||
'amaya' => "amaya/([0-9.]{1,10})",
|
||||
'aol' => "aol[ /\-]([0-9.]{1,10})",
|
||||
'camino' => "camino/([0-9.+]{1,10})",
|
||||
'chimera' => "chimera/([0-9.+]{1,10})",
|
||||
'chrome' => "Chrome/([0-9.]{1,10})",
|
||||
'curl' => "curl[ /]([0-9.]{1,10})",
|
||||
'firebird' => "Firebird/([0-9.+]{1,10})",
|
||||
'firefox' => "Firefox/([0-9.+]{1,10})",
|
||||
'lotus' => "Lotus[ \-]?Notes[ /]([0-9.]{1,10})",
|
||||
'konqueror' => "konqueror/([0-9.]{1,10})",
|
||||
'lynx' => "lynx/([0-9a-z.]{1,10})",
|
||||
'maxthon' => " Maxthon[\);]",
|
||||
'omniweb' => "omniweb/[ a-z]?([0-9.]{1,10})$",
|
||||
'opera' => "opera[ /]([0-9.]{1,10})",
|
||||
'safari' => "version/([0-9.]{1,10})\s+?safari/([0-9.]{1,10})",
|
||||
'webtv' => "webtv[ /]([0-9.]{1,10})",
|
||||
'netscape' => "^mozilla/([0-4]\.[0-9.]{1,10})",
|
||||
'mozilla' => "^mozilla/([5-9]\.[0-9a-z.]{1,10})",
|
||||
'xbox' => "\(compatible; MSIE[ /]([0-9.]{1,10})(.*)Xbox",
|
||||
'explorer' => "\(compatible; MSIE[ /]([0-9.]{1,10})",
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief List of Facebook IP addresses
|
||||
* @see <a href='https://developers.facebook.com/docs/ApplicationSecurity/#facebook_scraper'>Facebook application security</a>
|
||||
* @note List pulled via suggested whois command on Sep 26 2013
|
||||
*/
|
||||
protected $facebookIpRange = array(
|
||||
'204.15.20.0/22', '69.63.176.0/20', '66.220.144.0/20', '66.220.144.0/21', '69.63.184.0/21', '69.63.176.0/21', '74.119.76.0/22', '69.171.255.0/24', '173.252.64.0/18',
|
||||
'69.171.224.0/19', '69.171.224.0/20', '103.4.96.0/22', '69.63.176.0/24', '173.252.64.0/19', '173.252.70.0/24', '31.13.64.0/18', '31.13.24.0/21', '66.220.152.0/21',
|
||||
'66.220.159.0/24', '69.171.239.0/24', '69.171.240.0/20', '31.13.64.0/19', '31.13.64.0/24', '31.13.65.0/24', '31.13.67.0/24', '31.13.68.0/24', '31.13.69.0/24',
|
||||
'31.13.70.0/24', '31.13.71.0/24', '31.13.72.0/24', '31.13.73.0/24', '31.13.74.0/24', '31.13.75.0/24', '31.13.76.0/24', '31.13.77.0/24', '31.13.96.0/19', '31.13.66.0/24',
|
||||
'173.252.96.0/19', '69.63.178.0/24', '31.13.78.0/24', '31.13.79.0/24', '31.13.80.0/24', '31.13.82.0/24', '31.13.83.0/24', '31.13.84.0/24', '31.13.85.0/24', '31.13.86.0/24',
|
||||
'31.13.87.0/24', '31.13.88.0/24', '31.13.89.0/24', '31.13.90.0/24', '31.13.91.0/24', '31.13.92.0/24', '31.13.93.0/24', '31.13.94.0/24', '31.13.95.0/24', '69.171.253.0/24',
|
||||
'69.63.186.0/24', '31.13.81.0/24', '69.63.184.0/21', '2620:0:1c00::/40',
|
||||
'2a03:2880::/32', '2401:DB00::/32', '2a03:2880:fffe::/48', '2a03:2880:ffff::/48', '2620:0:1cff::/48', '2a03:2880:f000::/48', '2a03:2880:f001::/48', '2a03:2880:f002::/48',
|
||||
'2a03:2880:f003::/48', '2a03:2880:f004::/48', '2a03:2880:f005::/48', '2a03:2880:f006::/48', '2a03:2880:f007::/48', '2a03:2880:f008::/48', '2a03:2880:f009::/48', '2a03:2880:f00a::/48',
|
||||
'2a03:2880:f00b::/48', '2a03:2880:f00c::/48', '2a03:2880:f00d::/48', '2a03:2880:f00e::/48', '2a03:2880:f00f::/48', '2a03:2880:f010::/48', '2a03:2880:f011::/48', '2a03:2880:f012::/48',
|
||||
'2a03:2880:f013::/48', '2a03:2880:f014::/48', '2a03:2880:f015::/48', '2a03:2880:f016::/48'
|
||||
);
|
||||
|
||||
/**
|
||||
* Verify a supplied IP address is within the Facebook range
|
||||
*
|
||||
* @param string $ip IP address to check
|
||||
* @return bool
|
||||
* @see <a href='http://stackoverflow.com/questions/7951061/matching-ipv6-address-to-a-cidr-subnet'>Stackoverflow: check IPv6 against CIDR</a>
|
||||
* @see <a href='http://stackoverflow.com/questions/594112/matching-an-ip-to-a-cidr-mask-in-php5'>Stackoverflow: check IPv4 against CIDR</a>
|
||||
*/
|
||||
public function facebookIpVerified( $ip )
|
||||
{
|
||||
/* Is this an IPv6 address? */
|
||||
if( \strpos( $ip, ':' ) !== FALSE )
|
||||
{
|
||||
$ip = $this->_convertCompressedIpv6ToBits( inet_pton( $ip ) );
|
||||
|
||||
foreach( $this->facebookIpRange as $range )
|
||||
{
|
||||
if( \strpos( $range, ':' ) === FALSE )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
list( $net, $maskBits ) = explode( '/', $range );
|
||||
|
||||
$net = $this->_convertCompressedIpv6ToBits( inet_pton( $net ) );
|
||||
|
||||
if( $_checkIp == $_checkNet )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach( $this->facebookIpRange as $range )
|
||||
{
|
||||
if( \strpos( $range, ':' ) !== FALSE )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
list( $net, $maskBits ) = explode( '/', $range );
|
||||
|
||||
if( ( ip2long( $ip ) & ~( ( 1 << ( 32 - $maskBits ) ) - 1 ) ) == ip2long( $net ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an IPv6 address to bits
|
||||
*
|
||||
* @param string $ip Compressed IPv6 address
|
||||
* @return array
|
||||
* @see <a href='http://stackoverflow.com/questions/7951061/matching-ipv6-address-to-a-cidr-subnet'>Stackoverflow: check IPv6 against CIDR</a>
|
||||
*/
|
||||
protected function _convertCompressedIpv6ToBits( $ip )
|
||||
{
|
||||
$unpackedAddress = unpack( 'A16', $ip );
|
||||
$unpackedAddress = str_split( $unpackedAddress[1] );
|
||||
$ipAddress = '';
|
||||
|
||||
foreach( $unpackedAddress as $char )
|
||||
{
|
||||
$ipAddress .= str_pad( decbin( ord( $char ) ), 8, '0', STR_PAD_LEFT );
|
||||
}
|
||||
|
||||
return $ipAddress;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user