<?php
/**
 *	WP-SpamShield Utilities
 *	File Version 1.9.45
 */

/* Make sure file remains secure if called directly */
if( !defined( 'ABSPATH' ) || !defined( 'WPSS_VERSION' ) ) {
	if( !headers_sent() ) { @header( 'HTTP/1.0 403 Forbidden', TRUE, 403 ); @header( 'X-Robots-Tag: noindex', TRUE ); }
	die( 'ERROR: Direct access to this file is not allowed.' );
}
/* Prevents unintentional error display if WP_DEBUG not enabled. */
if( TRUE !== WP_DEBUG && TRUE !== WPSS_DEBUG ) { @ini_set( 'display_errors', 0 ); @error_reporting( 0 ); }

class WPSS_Utils extends WP_SpamShield {

	/**
	 *	WP-SpamShield Utility Class
	 *	Common utility functions
	 *	Child classes: WPSS_PHP, ...
	 *	@since	1.9.9.8.2
	 */

	/* Initialize Class Variables */
	static protected	$pref				= 'WPSS_';
	static protected	$debug_server		= '.redsandmarketing.com';
	static protected	$dev_url			= 'https://www.redsandmarketing.com/';
	static protected	$api				= 'api';
	static protected	$api_ver			= 'v2';
	static protected	$api_url			= NULL;
	static public		$_ENV				= array();
	static protected	$ip_dns_params		= array( 'server_hostname' => WPSS_SERVER_HOSTNAME, 'server_addr' => WPSS_SERVER_ADDR, 'server_name' => WPSS_SERVER_NAME, 'domain' => WPSS_SITE_DOMAIN );
	static protected	$php_version		= PHP_VERSION;
	static protected	$wp_ver				= WPSS_WP_VERSION;
	static protected	$plugin_name		= WPSS_PLUGIN_NAME;
	static protected	$rgx_tld			= WPSS_RGX_TLD;
	static protected	$safe_array_max		= NULL;
	static protected	$web_host			= NULL;
	static protected	$web_host_proxy		= NULL;
	static protected	$ip_addr			= NULL;
	static protected	$rev_dns_cache		= NULL;
	static protected	$fwd_dns_cache		= NULL;
	static protected	$rambaldi			= '<?php exit(0); ?>';

	function __construct() {
		/**
		 *	Do nothing...for now
		 */
	}

	/**
	 *	Convert a multi-dimensional array to a single-dimensional array.
	 *	@dependencies	none
	 *	@used by		WPSS_Utils::copy_dir_deep(), WPSS_Utils::mk_checksums(), WPSS_PHP::rmdir_deep()
	 *	@since			1.9.31
	 */
	static public function array_flatten( $arr ) {
		$return = array();
		array_walk_recursive( $arr, function( $a ) use ( &$return ) { $return[] = $a; } );
		return $return;
	}

	/**
	 *	Check if the config file exists.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.xx
	 */

	/**
	 *	Check if an IP matches CIDR. (IPv4)
	 *	Basic. Requires properly formatted IPv4 (xxx.xxx.xxx.xxx) and CIDR (xxx.xxx.xxx.xxx/xx)
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.35
	 */
	static public function cidr_match_ipv4( $ip, $cidr ) {
		if( empty( $ip ) || empty( $cidr ) || !is_string( $ip ) || !is_string( $cidr ) || FALSE === strpos( $cidr, '/' ) || FALSE === strpos( $ip, '.' ) || FALSE !== strpos( $ip, ':' ) || !parent::is_valid_ip( $ip, TRUE ) ) { return NULL; }
		list( $subnet, $mask ) = explode( '/', $cidr );
		if( empty( $subnet ) || empty( $mask ) || !parent::is_valid_ip( $subnet, TRUE ) ) { return NULL; }
		return ( ( ip2long( $ip ) & ~( ( 1 << ( 32 - $mask ) ) - 1 ) ) == ip2long( $subnet ) );
	}

	/**
	 *	Copy directory and all included contents. If it does not exist, create the dir and copy files. Recursive.
	 *	@dependencies	WPSS_PHP::scandir_deep(), WPSS_Utils::array_flatten(), WPSS_Utils::sort_unique(), WPSS_Utils::sort_by_strlen(), WPSS_PHP::copy(), ...
	 *	@used by		...
	 *	@since			1.9.xx
	 */

	/**
	 *	Deconflict an array of options
	 *	@used by		...
	 *	@since			1.9.xx
	 */

	/**
	 *	Delete the cache directory. Use when uninstalling.
	 *	@dependencies	WPSS_PHP::rmdir_deep()
	 *	@used by		...
	 *	@since			1.9.xx
	 */

	/**
	 *	Delete files in the cache 'tmp' directory.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.xx
	 */

	/**
	 *	Filter an option
	 *	@used by		...
	 *	@since			1.9.xx
	 */

	/**
	 *	Check if for cached version of data, and it it exists, retrieve.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.xx
	 *	@param			string		$slug		Slug of filename to retrieve.
	 *	@param			integer		$m			Interval in minutes. Default is 30 minutes.
	 *	@param			bool		$bak		If TRUE, retrieve a backup file.
	 *	@param			bool		$cnf		If TRUE, retrieve a config data file. Overrides `$bak`.
	 */

	/**
	 *	Get data from the WP-SpamShield config file. Wrapper for `WPSS_Utils::get_cache_data()`.
	 *	@dependencies	WPSS_Utils::get_cache_data()
	 *	@used by		...
	 *	@since			1.9.xx
	 *	@return			array
	 */

	/**
	 *	Get Crypto keys.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.xx
	 */

	/**
	 *	@alias of 		rs_wpss_get_forward_dns()
	 *	@used by		...
	 *	@since			1.9.9.8.7
	 */
	static public function get_forward_dns( $domain ) {
		return rs_wpss_get_forward_dns( $domain );
	}

	/**
	 *	Get IP/DNS Params
	 *	@dependencies	none
	 *	@used by		WPSS_Utils::get_web_host(), WPSS_Utils::get_web_proxy()
	 *	@since			WPSS 1.9.9.8.2, RSSD 1.0.6
	 */
	static public function get_ip_dns_params() {
		self::$ip_dns_params =
			array(
				'server_hostname'	=> WPSS_SERVER_HOSTNAME,
				'server_addr'		=> WPSS_SERVER_ADDR,
				'domain'			=> WPSS_SITE_DOMAIN,
			);
		return self::$ip_dns_params;
	}

	/**
	 *	Get reverse block pattern of IP (IPv4 only)
	 *	If IP comes in AA.BB.CC.DD format, return: DD.CC.BB.AA
	 *	@dependencies	WP_SpamShield::is_valid_ip()
	 *	@used by		spammy_domain_chk()
	 *	@since			1.9.9.8.2
	 */
	static public function get_ipv4_dcba( $ip ) {
		if( empty( $ip ) || FALSE === strpos( $ip, '.' ) || !parent::is_valid_ip( $ip ) ) { return $ip; }
		$ip_blocks_arr = explode( '.', $ip ); krsort( $ip_blocks_arr ); $ip_dcba = implode( '.', $ip_blocks_arr );
		return $ip_dcba;
	}

	/**
	 *	@alias of 		rs_wpss_get_ns()
	 *	@used by		...
	 *	@since			1.9.9.8.2
	 */
	static public function get_ns( $domain ) {
		return rs_wpss_get_ns( $domain );
	}

	/**
	 *	Get WPSS API Proxy URL
	 *	@dependencies	...
	 *	@used by		WP_SpamShield::get_headers(), ...
	 *	@since			1.9.40
	 */
	static public function get_api_proxy_url( $url ) {
		return ( empty( $url ) || !is_string( $url ) ) ? '' : ( self::get_api_url() . implode( '/', array( 'proxy', WPSS_Func::endo( $url ) ) ) . '/' );
	}

	/**
	 *	Get WPSS API URL (Base URL)
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.40
	 */
	static public function get_api_url() {
		if( !empty( self::$api_url ) ) { return self::$api_url; }
		self::$api_url = self::$dev_url . implode( '/', array( self::$api, self::$api_ver ) ) . '/';
		return self::$api_url;
	}

	/**
	 *	Get Data URI
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.42
	 */
	static public function get_data_uri( $data, $type = 'ext', $mime = '', $endo = TRUE ) {
		if( empty( $data ) || !is_string( $data ) ) { return ''; }
		$data	= ( ( FALSE !== $endo ) ? WPSS_Utils::endo( $data ) : $data );
		$scheme	= 'data:' . ( ( 'int' === $type ) ? '//' : '' );
		$mime	= ( empty( $mime ) ) ? ( implode( ';', array( 'text/plain', 'charset=utf-8' ) ) . ';' ) : $mime;
		$enc	= 'base64,';
		return implode( '', array( $scheme, $mime, $enc, $data ) );
	}

	/**
	 *	static public function get_real_ip_addr() {
	 * 		// In Development
	 *	}
	 */

	/**
	 *	@alias of 		rs_wpss_get_reverse_dns()
	 *	@used by		...
	 *	@since			1.9.9.8.2
	 */
	static public function get_reverse_dns( $ip ) {
		return rs_wpss_get_reverse_dns( $ip );
	}

	/**
	 *	Detect the safe max number of array elements for site's current setup based on PHP version and max memory. (Approximate)
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.xx
	 */

	/**
	 *	@alias of 		rs_wpss_get_server_addr()
	 *	@used by		...
	 *	@since			1.9.9.8.2
	 */
	static public function get_server_addr() {
		return rs_wpss_get_server_addr();
	}

	/**
	 *	@alias of 		rs_wpss_get_server_hostname()
	 *	@used by		...
	 *	@since			1.9.9.8.2
	 */
	static public function get_server_hostname( $sanitize = FALSE, $server_hostname = NULL ) {
		return rs_wpss_get_server_hostname( $sanitize, $server_hostname );
	}

	/**
	 *	@alias of 		rs_wpss_get_server_name()
	 *	@used by		...
	 *	@since			1.9.9.8.2
	 */
	static public function get_server_name() {
		return rs_wpss_get_server_name();
	}

	/**
	 *	Attempt to detect and identify web host
	 *	Web hosts detected: 100+
	 *	- TO DO:
	 *		- If Web Host is not detected below, query the API for more complete/up-to-date data.
	 *		- Get CIDR and ASN data from API
	 *	@dependencies	WPSS_Utils::get_option(), WPSS_Utils::update_option(), WPSS_Utils::get_server_hostname(), WPSS_Utils::get_ip_dns_params(), WPSS_Utils::get_reverse_dns(), WP_SpamShield::is_valid_ip(), WPSS_Utils::get_ns(), WPSS_Utils::sort_unique()
	 *	@used by		...
	 *	@func_ver		WPSS.20191015.01
	 *	@since			WPSS 1.9.9.8.2, RSSD 1.0.3
	 */
	static public function get_web_host( $params = array() ) {
		if( !empty( self::$web_host ) ) { return self::$web_host; }
		self::$web_host = parent::get_option( 'web_host' );
		if( !empty( self::$web_host ) ) { return self::$web_host; }
		if( empty( $params ) || !is_array( $params ) ) { $params = self::get_ip_dns_params(); }; extract( $params );
		self::$web_host					= FALSE;
		$server_hostname				= ( !empty( $server_hostname ) ) ? self::get_server_hostname( TRUE, $server_hostname ) : '';
		/* $_SERVER and $_ENV Variables */
		$web_hosts_ev = array(
			'DreamHost'					=> array( 'slug' => 'dreamhost', 'webhost' => 'DreamHost', 'envars' => 'DH_USER', 'deps' => 'ABSPATH', ), 
			'GoDaddy'					=> array( 'slug' => 'godaddy', 'webhost' => 'GoDaddy', 'envars' => 'GD_PHP_HANDLER,GD_ERROR_DOC', ), 
			'WP Engine'					=> array( 'slug' => 'wp-engine', 'webhost' => 'WP Engine', 'envars' => 'IS_WPE', ), 
		);
		/* PHP Constants */
		$web_hosts_cn = array(
			'Pagely'					=> array( 'slug' => 'pagely', 'webhost' => 'Pagely', 'constants' => 'PAGELYBIN', ),
			'WP Engine'					=> array( 'slug' => 'wp-engine', 'webhost' => 'WP Engine', 'constants' => 'WPE_APIKEY,WPE_PLUGIN_BASE,WPE_PLUGIN_VERSION', ),
		);
		/* Classes */
		$web_hosts_cl = array(
			'WP Engine'					=> array( 'slug' => 'wp-engine', 'webhost' => 'WP Engine', 'classes' => 'WPE_API,WpeCommon', ),
		);
		/**
		 *	Strings
		 *	Nameservers, Internal Server Names, or RevDNS of Website IP
		 *	Test $site_ns, $server_hostname, & $server_rev_dns
		 */
		$web_hosts_st = array(
			'100TB'						=> array( 'slug' => '100tb', 'webhost' => '100TB', 'domains' => '100tb.com', 'parent' => 'uk2', ), 
			'1and1 Internet'			=> array( 'slug' => '1and1', 'webhost' => '1and1 Internet', 'domains' => '1and1.co.uk,1and1.com,1and1.de,1und1.de,1and1-dns.biz,1and1-dns.com,1and1-dns.de,1and1-dns.org,oneandone.com,oneandone.net,ionos.com', ), 
			'A Small Orange'			=> array( 'slug' => 'a-small-orange', 'webhost' => 'A Small Orange', 'domains' => 'asmallorange.com,asodns.com,asonoc.com,asoshared.com', ), 
			'A2 Hosting'				=> array( 'slug' => 'a2-hosting', 'webhost' => 'A2 Hosting', 'domains' => 'a2hosting.com,a2hosted.com,a2dns.com,a2webhosting.com,cloudgdlx.com,supercp.com', ), 
			'Altervista'				=> array( 'slug' => 'altervista', 'webhost' => 'Altervista', 'domains' => 'altervista.com,altervista.org,altervista.it', 'tags' => 'freehost' ), 
			'Amazon Web Services (AWS)'	=> array( 'slug' => 'amazon-aws', 'webhost' => 'Amazon Web Services (AWS)', 'domains' => 'amazonaws.com', ), 
			'Amen'						=> array( 'slug' => 'amen', 'webhost' => 'Amen', 'domains' => 'amen.fr', ), 
			'Arvixe'					=> array( 'slug' => 'arvixe', 'webhost' => 'Arvixe', 'domains' => 'arvixe.com,arvixeshared.com,arvixevps.com', ), 
			'Automattic'				=> array( 'slug' => 'automattic', 'webhost' => 'Automattic', 'domains' => 'automattic.com', ), 
			'BigScoots'					=> array( 'slug' => 'bigscoots', 'webhost' => 'BigScoots', 'domains' => 'bigscoots.com', ), 
			'Bluehost'					=> array( 'slug' => 'bluehost', 'webhost' => 'Bluehost', 'domains' => 'bluehost.com,mybluehost.me', 'tags' => 'top' ), 
			'Cloudways'					=> array( 'slug' => 'cloudways', 'webhost' => 'Cloudways', 'domains' => 'cloudways.,cloudwaysapps.', ), 
			'Codero'					=> array( 'slug' => 'codero', 'webhost' => 'Codero', 'domains' => 'codero.com,codero.net', ), 
			'Cogeco Peer 1'				=> array( 'slug' => 'cogeco-peer-1', 'webhost' => 'Cogeco Peer 1', 'domains' => 'peer1.net', ), 
			'ColoCrossing'				=> array( 'slug' => 'colocrossing', 'webhost' => 'ColoCrossing', 'domains' => 'colocrossing.com,vsnx.net', ), 
			'DigitalOcean'				=> array( 'slug' => 'digitalocean', 'webhost' => 'DigitalOcean', 'domains' => 'digitalocean.com', ), 
			'Doteasy'					=> array( 'slug' => 'doteasy', 'webhost' => 'Doteasy', 'domains' => 'doteasy.com', ), 
			'DreamHost'					=> array( 'slug' => 'dreamhost', 'webhost' => 'DreamHost', 'domains' => 'dreamhost.com,dreamhosters.com,dreamhostps.com', ), 
			'eHost'						=> array( 'slug' => 'ehost', 'webhost' => 'eHost', 'domains' => 'ehost.com', ), 
			'Enzu'						=> array( 'slug' => 'enzu', 'webhost' => 'Enzu', 'domains' => 'scalabledns.com', ), 
			'EuHost'					=> array( 'slug' => 'euhost', 'webhost' => 'EuHost', 'domains' => 'euhost.co.uk', ), 
			'eUKhost'					=> array( 'slug' => 'eukhost', 'webhost' => 'eUKhost', 'domains' => 'eukhost.com', ), 
			'Fasthosts'					=> array( 'slug' => 'fasthosts', 'webhost' => 'Fasthosts', 'domains' => 'fast-hosts.org,fasthosts.co.uk,fasthosts.net.uk', ), 
			'FatCow'					=> array( 'slug' => 'fatcow', 'webhost' => 'FatCow', 'domains' => 'fatcow.com', ), 
			'Flywheel'					=> array( 'slug' => 'flywheel', 'webhost' => 'Flywheel', 'domains' => 'flywheelsites.com,getflywheel.com', ), 
			'Gandi'						=> array( 'slug' => 'gandi', 'webhost' => 'Gandi', 'domains' => 'gandi.net', ), 
			'Globat'					=> array( 'slug' => 'globat', 'webhost' => 'Globat', 'domains' => 'dnsjunction.com,globat.com', ), 
			'GlowHost'					=> array( 'slug' => 'glowHost', 'webhost' => 'GlowHost', 'domains' => 'glowhost.com', ), 
			'GoDaddy'					=> array( 'slug' => 'godaddy', 'webhost' => 'GoDaddy', 'domains' => 'godaddy.com,secureserver.net,myftpupload.com', ), 
			'Google Cloud Platform'		=> array( 'slug' => 'google-cloud', 'webhost' => 'Google Cloud Platform', 'domains' => 'bc.googleusercontent.com,googledomains.com,googleusercontent.com', ), 
			'GreenGeeks'				=> array( 'slug' => 'greengeeks', 'webhost' => 'GreenGeeks', 'domains' => 'greengeeks.com', ), 
			'Heart Internet'			=> array( 'slug' => 'heart-internet', 'webhost' => 'Heart Internet', 'domains' => 'heartinternet.co.uk,heartinternet.uk,mainnameserver.com', 'parent' => 'hosteurope', ), 
			'Hetzner'					=> array( 'slug' => 'hetzner', 'webhost' => 'Hetzner', 'domains' => 'hetzner.,host-h.net,your-server.de', ), 
			'HostDime'					=> array( 'slug' => 'hostdime', 'webhost' => 'HostDime', 'domains' => 'dimenoc.com', ), 
			'HostEurope'				=> array( 'slug' => 'hosteurope', 'webhost' => 'HostEurope', 'domains' => 'hosteurope.de,hosteurope.com,server4you.de,server4you.com,server4you.net', ), 
			'HostGator'					=> array( 'slug' => 'hostgator', 'webhost' => 'HostGator', 'domains' => 'hostgator.com,hostgator.com.br,hostgatorwebservers.com,seohosting.com,unifiedlayer.com,websitewelcome.com', 'tags' => 'top' ), 
			'HostIndia.net'				=> array( 'slug' => 'hostindia', 'webhost' => 'HostIndia.net', 'domains' => 'hostindia.net', ), 
			'HostingCentre'				=> array( 'slug' => 'hostingcentre', 'webhost' => 'HostingCentre', 'domains' => 'hostingcentre.in', ), 
			'Hostinger'					=> array( 'slug' => 'hostinger', 'webhost' => 'Hostinger', 'domains' => 'hostinger.,main-hosting.com,niagahoster.com,hosting24.com,000webhostapp.com,000webhost.com', ), 
			'HostingRaja'				=> array( 'slug' => 'hostingraja', 'webhost' => 'HostingRaja', 'domains' => 'hostingraja.in', ), 
			'HostMetro'					=> array( 'slug' => 'hostmetro', 'webhost' => 'HostMetro', 'domains' => 'hostmetro.com', ), 
			'HostMonster'				=> array( 'slug' => 'hostmonster', 'webhost' => 'HostMonster', 'domains' => 'hostmonster.com', ), 
			'HostNine'					=> array( 'slug' => 'hostnine', 'webhost' => 'HostNine', 'domains' => 'cirtexhosting.com,hostnine.com', ), 
			'HostPapa'					=> array( 'slug' => 'hostpapa', 'webhost' => 'HostPapa', 'domains' => 'hostpapa.com,hostpapavps.net', ), 
			'Hostway'					=> array( 'slug' => 'hostway', 'webhost' => 'Hostway', 'domains' => 'hostway.net', ), 
			'Hostwinds'					=> array( 'slug' => 'hostwinds', 'webhost' => 'Hostwinds', 'domains' => 'hostwinds.com,hostwindsdns.com', ), 
			'Infomaniak'				=> array( 'slug' => 'infomaniak', 'webhost' => 'Infomaniak', 'domains' => 'infomaniak.ch', ), 
			'InMotion Hosting'			=> array( 'slug' => 'inmotion-hosting', 'webhost' => 'InMotion Hosting', 'domains' => 'inmotionhosting.com,servconfig.com', 'tags' => 'top' ), 
			'IO Zoom'					=> array( 'slug' => 'io-zoom', 'webhost' => 'IO Zoom', 'domains' => 'iozoom.com', ), 
			'Iomart'					=> array( 'slug' => 'Iomart', 'webhost' => 'Iomart', 'domains' => 'iomart.com,rapidswitch.com,redstation.co.uk,redstation.com', ), 
			'iPage'						=> array( 'slug' => 'ipage', 'webhost' => 'iPage', 'domains' => 'ipage.com', ), 
			'IPOWER'					=> array( 'slug' => 'ipower', 'webhost' => 'IPOWER', 'domains' => 'ipower.com,ipowerdns.com,ipowerweb.net', ), 
			'IX Web Hosting'			=> array( 'slug' => 'ix-web-hosting', 'webhost' => 'IX Web Hosting', 'domains' => 'cloudbyix.com,cloudix.com,ecommerce.com,hostexcellence.com,ixwebhosting.com,ixwebsites.com,opentransfer.com,webhost.biz', ), 
			'JustHost'					=> array( 'slug' => 'justhost', 'webhost' => 'JustHost', 'domains' => 'justhost.com', ), 
			'Krystal Hosting'			=> array( 'slug' => 'krystal-hosting', 'webhost' => 'Krystal Hosting', 'domains' => 'krystal.co.uk', ), 
			'LeaseWeb'					=> array( 'slug' => 'leaseweb', 'webhost' => 'LeaseWeb', 'domains' => 'leaseweb.com,leaseweb.net,leaseweb.nl,lswcdn.com,shore.net', ), 
			'Lightning Base'			=> array( 'slug' => 'lightning-base', 'webhost' => 'Lightning Base', 'domains' => 'lightningbase.com', ), 
			'Linode'					=> array( 'slug' => 'linode', 'webhost' => 'Linode', 'domains' => 'linode.com', ), 
			'Liquid Web'				=> array( 'slug' => 'liquid-web', 'webhost' => 'Liquid Web', 'domains' => 'liquidweb.com,wiredtree.com', ), 
			'Lunarpages'				=> array( 'slug' => 'lunarpages', 'webhost' => 'Lunarpages', 'domains' => 'lunarfo.com,lunarpages.com,lunarservers.com', ), 
			'Media Temple'				=> array( 'slug' => 'media-temple', 'webhost' => 'Media Temple', 'domains' => 'mediatemple.com,mediatemple.net,gridserver.com,mtsvc.net', ), 
			'Microsoft Azure'			=> array( 'slug' => 'microsoft-azure', 'webhost' => 'Microsoft Azure', 'domains' => 'azuredns-cloud.net,azurewebsites.net', ),
			'Midphase'					=> array( 'slug' => 'midphase', 'webhost' => 'Midphase', 'domains' => 'midphase.com,anhosting.com,us2.net', 'parent' => 'uk2', ),
			'My Wealthy Affiliate'		=> array( 'slug' => 'my-wealthy-affiliate', 'webhost' => 'My Wealthy Affiliate', 'domains' => 'mywahosting.com', ), 
			'MyHosting.com'				=> array( 'slug' => 'myhosting', 'webhost' => 'MyHosting.com', 'domains' => 'myhosting.com', ), 
			'Namecheap Hosting'			=> array( 'slug' => 'namecheap-hosting', 'webhost' => 'Namecheap Hosting', 'domains' => 'namecheap.com,namecheaphosting.com,registrar-servers.com,web-hosting.com', ), 
			'NetFirms'					=> array( 'slug' => 'netfirms', 'webhost' => 'NetFirms', 'domains' => 'netfirms.com', ), 
			'Nexcess'					=> array( 'slug' => 'nexcess', 'webhost' => 'Nexcess', 'domains' => 'nexcess.net', ), 
			'NFrance'					=> array( 'slug' => 'nfrance', 'webhost' => 'NFrance', 'domains' => 'slconseil.com', ), 
			'Omnis'						=> array( 'slug' => 'omnis', 'webhost' => 'Omnis', 'domains' => 'omnis.com,omnisdns.net', ), 
			'One.com'					=> array( 'slug' => 'one-com', 'webhost' => 'One.com', 'domains' => 'b-one.net,b-one-dns.net,one.com', ), 
			'Online.net'				=> array( 'slug' => 'online-net', 'webhost' => 'Online.net', 'domains' => 'online.net,poneytelecom.eu', ), 
			'OVH Hosting'				=> array( 'slug' => 'ovh-hosting', 'webhost' => 'OVH Hosting', 'domains' => 'anycast.me,ovh.co.uk,ovh.com,ovh.net,ovh.pl', ), 
			'Pagely'					=> array( 'slug' => 'pagely', 'webhost' => 'Pagely', 'domains' => 'pagely.com,pagelyhosting.com', ), 
			'Pair Networks'				=> array( 'slug' => 'pair-networks', 'webhost' => 'Pair Networks', 'domains' => 'ns0.com,pair.com,pairvps.com', ), 
			'Pantheon'					=> array( 'slug' => 'pantheon', 'webhost' => 'Pantheon', 'domains' => 'pantheon.io,pantheonsite.io', ), 
			'PHPNET'					=> array( 'slug' => 'phpnet', 'webhost' => 'PHPNET', 'domains' => 'phpnet.org', ), 
			'PlusServer'				=> array( 'slug' => 'plusserver', 'webhost' => 'PlusServer', 'domains' => 'plusserver.com', ), 
			'PowWeb'					=> array( 'slug' => 'powweb', 'webhost' => 'PowWeb', 'domains' => 'powweb.com', ), 
			'Pressable'					=> array( 'slug' => 'pressable', 'webhost' => 'Pressable', 'domains' => 'zippykid.com', ), 
			'QuadraNet'					=> array( 'slug' => 'quadranet', 'webhost' => 'QuadraNet', 'domains' => 'quadranet.com', ), 
			'Rackspace'					=> array( 'slug' => 'rackspace', 'webhost' => 'Rackspace', 'domains' => 'hostingmatrix.net,rackspace.com,stabletransit.com', ), 
			'Register.com'				=> array( 'slug' => 'register-com', 'webhost' => 'Register.com', 'domains' => 'register.com', ), 
			'Reseller Club'				=> array( 'slug' => 'reseller-club', 'webhost' => 'Reseller Club', 'domains' => 'resellerclub.com,webhostbox.net', ), 
			'SingleHop'					=> array( 'slug' => 'singlehop', 'webhost' => 'SingleHop', 'domains' => 'singlehop.com,singlehop.net', ), 
			'Site5'						=> array( 'slug' => 'site5', 'webhost' => 'Site5', 'domains' => 'site5.com', ), 
			'SiteGround'				=> array( 'slug' => 'siteground', 'webhost' => 'SiteGround', 'domains' => 'siteground.', 'tags' => 'top' ), 
			'SiteRubix'					=> array( 'slug' => 'siterubix', 'webhost' => 'SiteRubix', 'domains' => 'siterubix.com', 'parent' => 'my-wealthy-affiliate', ), 
			'SoftLayer'					=> array( 'slug' => 'softlayer', 'webhost' => 'SoftLayer', 'domains' => 'networklayer.com,sl-reverse.com,softlayer.net', ), 
			'Superb'					=> array( 'slug' => 'superb', 'webhost' => 'Superb', 'domains' => 'superb.net', ), 
			'Triple C Cloud Computing'	=> array( 'slug' => 'triple-c', 'webhost' => 'Triple C Cloud Computing', 'domains' => 'ccc.net.il,ccccloud.com', ), 
			'TSO Host'					=> array( 'slug' => 'tso-host', 'webhost' => 'TSO Host', 'domains' => 'tsohost.co.uk,gridhost.co.uk', ), 
			'UK2'						=> array( 'slug' => 'uk2', 'webhost' => 'UK2', 'domains' => 'uk2.net', ), 
			'UnoEuro'					=> array( 'slug' => 'unoeuro', 'webhost' => 'UnoEuro', 'domains' => 'unoeuro.com', ), 
			'VHosting Solution'			=> array( 'slug' => 'vhosting', 'webhost' => 'VHosting Solution', 'domains' => 'vhosting-it.com', ), 
			'VPS.net'					=> array( 'slug' => 'vps-net', 'webhost' => 'VPS.net', 'domains' => 'vps.net', 'parent' => 'uk2', ), 
			'Vultr'						=> array( 'slug' => 'vultr', 'webhost' => 'Vultr', 'domains' => 'vultr.com,choopa.com,choopa.net,choopadns.com,reliableservers.com,unmeteredservers.com', ), 
			'Web Hosting Hub'			=> array( 'slug' => 'web-hosting-hub', 'webhost' => 'Web Hosting Hub', 'domains' => 'webhostinghub.com', ), 
			'Web.com'					=> array( 'slug' => 'web-com', 'webhost' => 'Web.com', 'domains' => 'web.com', ), 
			'WebFaction'				=> array( 'slug' => 'webfaction', 'webhost' => 'WebFaction', 'domains' => 'webfaction.com', ), 
			'WebHostingBuzz'			=> array( 'slug' => 'webhostingbuzz', 'webhost' => 'WebHostingBuzz', 'domains' => 'fastwhb.com,webhostingbuzz.com', ), 
			'Webs'						=> array( 'slug' => 'webs', 'webhost' => 'Webs', 'domains' => 'webs.com', ), 
			'WebSynthesis'				=> array( 'slug' => 'websynthesis', 'webhost' => 'WebSynthesis', 'domains' => 'websynthesis.com,wsynth.net', ), 
			'Weebly'					=> array( 'slug' => 'weebly', 'webhost' => 'Weebly', 'domains' => 'weebly.com', 'tags' => 'diy' ), 
			'WestHost'					=> array( 'slug' => 'westhost', 'webhost' => 'WestHost', 'domains' => 'westhost.net,setaptr.net', 'parent' => 'uk2', ), 
			'Wix'						=> array( 'slug' => 'wix', 'webhost' => 'Wix', 'domains' => 'wix.com,wixdns.net', 'tags' => 'diy' ), 
			'WordPress.com'				=> array( 'slug' => 'wordpress-com', 'webhost' => 'WordPress.com', 'domains' => 'wordpress.com', ), 
			'WP Engine'					=> array( 'slug' => 'wp-engine', 'webhost' => 'WP Engine', 'domains' => 'wpengine.com', 'phpver' => 'wpengine' ), 
		);
		/* RegEx - Nameservers, Internal Server Names, or RevDNS of Website IP - Test $site_ns, $server_hostname, & $server_rev_dns */
		$web_hosts_rg = array(
			'1and1 Internet'			=> array( 'slug' => '1and1', 'webhost' => '1and1 Internet', 'domainsrgx' => "~(^|\.)(ns\d*[\.\-])?(1[au]nd1([\.\-]ui)?(\-dns)?)(\.[a-z]{2,3}){1,2}[a-z]*$~i", ), 
			'Amazon Web Services (AWS)'	=> array( 'slug' => 'amazon-aws', 'webhost' => 'Amazon Web Services (AWS)', 'domainsrgx' => "~(^|\.)ns[\.\-]\d+\.awsdns\-\d+(\.[a-z]{2,3}){1,2}[a-z]*$~i", ), 
			'Cloudways'					=> array( 'slug' => 'cloudways', 'webhost' => 'Cloudways', 'domainsrgx' => "~(^|\.)cloudways(apps)?(\.[a-z]{2,3}){1,2}[a-z]*$~i", ), 
			'HostGator'					=> array( 'slug' => 'hostgator', 'webhost' => 'HostGator', 'domainsrgx' => "~(^|\.)(hostgator|websitewelcome)\.com~i", ), 
			'Hostinger'					=> array( 'slug' => 'hostinger', 'webhost' => 'Hostinger', 'domainsrgx' => "~(^|\.)(([a-z]{2})?hostinger(\-[a-z]{2})?)(\.[a-z]{2,3}){1,2}[a-z]*$~i", ), 
			'Hetzner'					=> array( 'slug' => 'hetzner', 'webhost' => 'Hetzner', 'domainsrgx' => "~(^|\.)(hetzner\.|host\-h\.net|your\-server\.de)~i", ), 
			'Liquid Web'				=> array( 'slug' => 'liquid-web', 'webhost' => 'Liquid Web', 'domainsrgx' => "~(^|\.)(liquidweb\.com|sourcedns\.com|wiredtree\.com|\w+\-liquidwebsites\.com)~i", ), 
			'SiteGround'				=> array( 'slug' => 'siteground', 'webhost' => 'SiteGround', 'domainsrgx' => "~(^|\.)(siteground|sg(srv|ded|vps)|clev)(\d+)?(\.[a-z]{2,3}){1,2}[a-z]*$~i", ), 
			'WebHostFace'				=> array( 'slug' => 'webhostface', 'webhost' => 'WebHostFace', 'domainsrgx' => "~(^|\.)(webhost(ing)?face([a-z0-9]+)?|face(ds|reseller|shared|vps)[a-z]{2,10}\d|whf(star|web))(\.[a-z]{2,3}){1,2}[a-z]*$~i", ), 
		);
		$web_hosts_ns = $web_hosts_st;

		/* Start Tests*/
		$server_rev_dns = self::get_reverse_dns( $server_addr );
		$server_rev_dns = ( !parent::is_valid_ip( $server_rev_dns ) ) ? $server_rev_dns : ''; /* If IP, will skip the check */
		foreach( (array) $web_hosts_st as $wh => $data ) {
			if( !empty( self::$web_host ) ) { break; }
			if( empty( $server_hostname ) && empty( $server_rev_dns ) ) { break; }
			$domains = explode( ',', $data['domains'] );
			foreach( (array) $domains as $st ) {
				if( !empty( self::$web_host ) ) { break; }
				if( !empty( $server_hostname ) && FALSE !== strpos( $server_hostname, '.'.$st ) ) {
					self::$web_host = $data['webhost'];
				} elseif( !empty( $server_rev_dns ) && FALSE !== strpos( $server_rev_dns, '.'.$st ) ) {
					self::$web_host = $data['webhost'];
				}
			}
			/* Check for custom/modified PHP versions used by host */
			$phpver = ( !empty( $data['phpver'] ) ) ? $data['phpver'] : '';
			if( !empty( $phpver ) && FALSE !== strpos( PHP_VERSION, $phpver ) ) {
				self::$web_host = $data['webhost'];
			}
		}
		foreach( (array) $web_hosts_rg as $wh => $data ) {
			if( !empty( self::$web_host ) ) { break; }
			if( empty( $server_hostname ) && empty( $server_rev_dns ) ) { break; }
			$rg = $data['domainsrgx'];
			if( !empty( $server_hostname ) && WP_SpamShield::preg_match( $rg, $server_hostname ) ) {
				self::$web_host = $data['webhost'];
			} elseif( !empty( $server_rev_dns ) && WP_SpamShield::preg_match( $rg, $server_rev_dns ) ) {
				self::$web_host = $data['webhost'];
			}
		}
		$site_ns = self::get_ns( $domain );
		$site_ns = ( !empty( $site_ns ) && is_array( $site_ns ) ) ? implode( '  |  ', self::sort_unique( $site_ns ) ) : 'Not Detected';
		foreach( (array) $web_hosts_ns as $wh => $data ) {
			if( !empty( self::$web_host ) ) { break; }
			if( empty( $site_ns ) && empty( $server_hostname ) && empty( $server_rev_dns ) ) { break; }
			$domains = explode( ',', $data['domains'] );
			foreach( (array) $domains as $st ) {
				if( !empty( self::$web_host ) ) { break; }
				if( !empty( $site_ns ) && FALSE !== strpos( $site_ns, '.'.$st ) ) {
					self::$web_host = $data['webhost'];
				} elseif( !empty( $server_hostname ) && FALSE !== strpos( $server_hostname, '.'.$st ) ) {
					self::$web_host = $data['webhost'];
				} elseif( !empty( $server_rev_dns ) && FALSE !== strpos( $server_rev_dns, '.'.$st ) ) {
					self::$web_host = $data['webhost'];
				}
			}
		}
		foreach( (array) $web_hosts_rg as $wh => $data ) {
			if( !empty( self::$web_host ) ) { break; }
			if( empty( $site_ns ) ) { break; }
			$rg = $data['domainsrgx'];
			if( !empty( $site_ns ) && WP_SpamShield::preg_match( $rg, $site_ns ) ) {
				self::$web_host = $data['webhost']; 
			}
		}
		foreach( (array) $web_hosts_ev as $wh => $data ) {
			if( !empty( self::$web_host ) ) { break; }
			$envars = explode( ',', $data['envars'] );
			foreach( (array) $envars as $ev ) {
				if( !empty( self::$web_host ) ) { break; }
				if( empty( $_SERVER[$ev] ) ) { continue; }
				if( empty( $data['deps'] ) ) {
					self::$web_host = $data['webhost'];
				} elseif( FALSE !== strpos( $data['deps'], $_SERVER[$ev] ) ) {
					self::$web_host = $data['webhost'];
				}
			}
		}
		foreach( (array) $web_hosts_cn as $wh => $data ) {
			if( !empty( self::$web_host ) ) { break; }
			$constants = explode( ',', $data['constants'] );
			foreach( (array) $constants as $cn ) {
				if( !empty( self::$web_host ) ) { break; }
				if( defined( $cn ) ) {
					self::$web_host = $data['webhost'];
				}
			}
		}
		foreach( (array) $web_hosts_cl as $wh => $data ) {
			if( !empty( self::$web_host ) ) { break; }
			$classes = explode( ',', $data['classes'] );
			foreach( (array) $classes as $cl ) {
				if( !empty( self::$web_host ) ) { break; }
				if( class_exists( $cl ) ) {
					self::$web_host = $data['webhost'];
				}
			}
		}
		if( !empty( self::$web_host ) ) {
			$options = array( 'web_host' => self::$web_host, );
			parent::update_option( $options );
		}
		return self::$web_host;
	}

	/**
	 *	Try to identify web host proxies: Proxies, CDNs, Web Application Firewalls (WAFs), etc.
	 *	@dependencies	WP_SpamShield::get_option(), WP_SpamShield::update_option(), WPSS_Utils::get_server_hostname(), WPSS_Utils::get_ip_dns_params(), WPSS_Utils::get_reverse_dns(), WP_SpamShield::is_valid_ip(), WPSS_Utils::get_ns(), WPSS_Utils::is_user_admin(), WPSS_Utils::sort_unique()
	 *	@used by		...
	 *	@func_ver		RSSD.20180925.01
	 *	@since			WPSS 1.9.9.8.2, RSSD 1.0.3
	 */
	static public function get_web_proxy( $params = array() ) {
		if( NULL !== self::$web_host_proxy ) { return self::$web_host_proxy; }
		self::$web_host_proxy = parent::get_option( 'web_proxy' );
		if( NULL !== self::$web_host_proxy ) { return self::$web_host_proxy; }
		if( empty( $params ) || !is_array( $params ) ) { $params = self::get_ip_dns_params(); }; extract( $params );
		self::$web_host_proxy			= FALSE;
		$server_hostname				= ( !empty( $server_hostname ) ) ? self::get_server_hostname( TRUE, $server_hostname ) : '';
		$server_rev_dns					= self::get_reverse_dns( $server_addr );
		$server_rev_dns					= ( !parent::is_valid_ip( $server_rev_dns ) ) ? $server_rev_dns : ''; /* If IP, will skip the check */
		/* $_SERVER and $_ENV Variables */
		$web_proxies_ev = array(
			'Cloudflare'				=> array( 'slug' => 'cloudflare', 'webproxy' => 'Cloudflare', 'envars' => 'HTTP_CF_CONNECTING_IP,HTTP_CF_IPCOUNTRY,HTTP_CF_RAY,HTTP_CF_VISITOR,HTTP_X_AMZ_CF_ID', ), 
			'Incapsula'					=> array( 'slug' => 'incapsula', 'webproxy' => 'Incapsula', 'envars' => 'HTTP_INCAP_CLIENT_IP', ), 
			'Sucuri CloudProxy'			=> array( 'slug' => 'sucuri-cloudproxy', 'webproxy' => 'Sucuri CloudProxy', 'envars' => 'HTTP_X_SUCURI_CLIENTIP', ), 
		);
		$web_proxies_px = array(			/* Proxies, CDNs, Web Application Firewalls (WAFs), etc. - Test $site_ns, $server_hostname, & $server_rev_dns */
			'Cloudflare'				=> array( 'slug' => 'cloudflare', 'webproxy' => 'Cloudflare', 'domains' => 'cloudflare.com,ns.cloudflare.com', ), /* HTTP Headers: HTTP:CF-Connecting-IP / $_SERVER['HTTP_CF_CONNECTING_IP'] */
			'Incapsula'					=> array( 'slug' => 'incapsula', 'webproxy' => 'Incapsula', 'domains' => 'incapdns.net,incapsecuredns.net', ), /* HTTP Headers: HTTP:Incap-Client-IP / $_SERVER['HTTP_INCAP_CLIENT_IP'] */
			'Sucuri CloudProxy'			=> array( 'slug' => 'sucuri-cloudproxy', 'webproxy' => 'Sucuri CloudProxy', 'domains' => 'mycloudproxy.com,sucuridns.com', ), /* HTTP Headers: HTTP:X-Sucuri-Client-IP / $_SERVER['HTTP_X_SUCURI_CLIENTIP'] */
		);
		$web_proxies_rg = array(			/* RegEx - Internal Server Names or RevDNS of Website IP - Test $server_hostname & $server_rev_dns */
			'Cloudflare'				=> array( 'slug' => 'cloudflare', 'webproxy' => 'Cloudflare', 'domainsrgx' => "~^(([a-z0-9]+\.)?ns\d*\.)?cloudflare\.com$~i", ), 
			'Sucuri CloudProxy'			=> array( 'slug' => 'sucuri-cloudproxy', 'webproxy' => 'Sucuri CloudProxy', 'domainsrgx' => "~^cloudproxy\d+\.sucuri\.net$~i", ), 
		);
		/* if( !empty( $_SERVER['HTTP_X_SUCURI_CLIENTIP'] ) ) { $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_SUCURI_CLIENTIP']; } */
		$options = array( 'surrogate' => FALSE, );
		$site_ns = (array) self::get_ns( $domain );
		$site_ns = ( !empty( $site_ns ) && is_array( $site_ns ) ) ? implode( '  |  ', self::sort_unique( $site_ns ) ) : $site_ns;
		foreach( (array) $web_proxies_ev as $wp => $data ) {
			$envars = explode( ',', $data['envars'] );
			foreach( (array) $envars as $ev ) {
				if( isset( $_SERVER[$ev] ) ) {
					self::$web_host_proxy = $data['webproxy'];
				}
			}
		}
		foreach( (array) $web_proxies_px as $px => $wp ) {
			if( !empty( self::$web_host_proxy ) ) { break; }
			if( empty( $site_ns ) && empty( $server_hostname ) && empty( $server_rev_dns ) ) { break; }
			if( !empty( $site_ns ) && FALSE !== strpos( $site_ns, $px ) ) {
				self::$web_host_proxy = $wp;
			} elseif( !empty( $server_hostname ) && FALSE !== strpos( $server_hostname, $px ) ) {
				self::$web_host_proxy = $wp;
			} elseif( !empty( $server_rev_dns ) && FALSE !== strpos( $server_rev_dns, $px ) ) {
				self::$web_host_proxy = $wp;
			}
		}
		foreach( (array) $web_proxies_rg as $wp => $data ) {
			if( !empty( self::$web_host_proxy ) ) { break; }
			if( empty( $site_ns ) && empty( $server_hostname ) && empty( $server_rev_dns ) ) { break; }
			$rg = $data['domainsrgx'];
			if( !empty( $site_ns ) && WP_SpamShield::preg_match( $rg, $site_ns ) ) {
				self::$web_host_proxy = $data['webproxy'];
			} elseif( !empty( $server_hostname ) && WP_SpamShield::preg_match( $rg, $server_hostname ) ) {
				self::$web_host_proxy = $data['webproxy'];
			} elseif( !empty( $server_rev_dns ) && WP_SpamShield::preg_match( $rg, $server_rev_dns ) ) {
				self::$web_host_proxy = $data['webproxy'];
			}
		}
		if( !empty( self::$web_host_proxy ) ) {
			$options = array( 'surrogate' => 1, 'disable_temp_blacklist' => 1, 'web_proxy' => self::$web_host_proxy, 'cloudflare' => ( ( 'Cloudflare' === self::$web_host_proxy ) ? 1 : 0 ), );
		} else {
			$options = array( 'cloudflare' => 0, );
		}
		parent::update_option( $options );
		return self::$web_host_proxy;
	}

	/**
	 *	Detect if Array is Associative
	 *	@dependencies	WPSS_Utils::obj_to_arr()
	 *	@used by		...
	 *	@func_ver		WPSS.20190916.01
	 *	@since			WPSS 1.9.9.8.2, RSSD 1.0.4
	 */
	static public function is_array_assoc( $arr = array() ) {
		if( empty( $arr ) || !is_array( $arr ) ) { return FALSE; }
		foreach( (array) $arr as $k => $v ) {
			if( !is_int( $k ) ) { return TRUE; }
		}
		return FALSE;
	}

	/**
	 *	Detect if Array is Multidimensional
	 *	@dependencies	WPSS_Utils::obj_to_arr()
	 *	@used by		WPSS_Utils::vsort_array(), WPSS_Utils::ksort_array(), WPSS_Utils::sort_unique(), ...
	 *	@func_ver		WPSS.20190916.01
	 *	@since			WPSS 1.9.9.8.2, RSSD 1.0.5
	 */
	static public function is_array_multi( $arr = array() ) {
		if( empty( $arr ) || !is_array( $arr ) ) { return FALSE; }
		foreach( (array) $arr as $k => $v ) {
			if( is_array( $v ) || is_object( $v ) ) { return TRUE; }
		}
		return FALSE;
	}

	/**
	 *	Detect if Array is Numerical
	 *	@dependencies	WPSS_Utils::obj_to_arr(), ...
	 *	@used by		...
	 *	@func_ver		WPSS.20190916.01
	 *	@since			WPSS 1.9.9.8.2, RSSD 1.0.5
	 */
	static public function is_array_num( $arr = array() ) {
		if( empty( $arr ) || !is_array( $arr ) ) { return FALSE; }
		foreach( (array) $arr as $k => $v ) {
			if( is_int( $k ) ) { return TRUE; }
		}
		return FALSE;
	}

	/**
	 *	Detect if string is Base64 encoded.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.31
	 */
	static public function is_b64( $str ) {
		return ( !empty( $str ) && is_string( $str ) && preg_match( "~^([A-Za-z0-9\+/]{4})*([A-Za-z0-9\+/]{4}|[A-Za-z0-9\+/]{3}\=|[A-Za-z0-9\+/]{2}\=\=)$~", $str ) );
	}

	/**
	 *	Check if current request is a CSP Report.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.9.8.2
	 */
	static public function is_csp_report() {
		return ( 'POST' === WPSS_REQUEST_METHOD && !empty( $_SERVER['CONTENT_TYPE'] ) && 'application/csp-report' === $_SERVER['CONTENT_TYPE'] );
	}

	/**
	 *	Check if specific ini value can be changed at runtime.
	 *	Conditional alias for WP Core function `wp_is_ini_value_changeable( $setting )`
	 *	@dependencies	WP_SpamShield::is_wp_ver(), ...
	 *	@used by		WPSS_Security::security_init(), ...
	 *	@since			1.9.9.9.2
	 */
	static public function is_ini_value_changeable( $setting ) {
		if( parent::is_wp_ver( '4.6' ) ) {
			return wp_is_ini_value_changeable( $setting );
		}
		return TRUE;
	}

	/**
	 *	Detect if string is JSON encoded.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.31
	 */
	static public function is_json( $str ) {
		return ( is_string( $str ) && is_array( @json_decode( $str, TRUE ) ) && ( @json_last_error() === JSON_ERROR_NONE ) );
	}

	/**
	 *	Detect if string is URL encoded data, like query string passed via a URL or generated with `http_build_query()`.
	 *	@dependencies	...
	 *	@used by		WPSS_PHP::parse_str(), ...
	 *	@since			1.9.31
	 */
	static public function is_parsable( $str ) {
		if( empty( $str ) || !is_string( $str ) ) { return FALSE; }
		parse_str( $str, $arr );
		return ( !empty( $arr ) && is_array( $arr ) );
	}

	/**
	 *	Detect if string is serialized data.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.35
	 */
	static public function is_serialized( $str ) {
		return ( is_string( $str ) && is_array( @unserialize( $str ) ) && FALSE !== @unserialize( $str ) );
	}

	/**
	 *	Detect if string is lower case.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.35
	 */
	static public function is_string_lc( $str ) {
		return ( !empty( $str ) && is_string( $str ) && WPSS_Func::lower( $str ) === $str );
	}

	/**
	 *	@alias of 		rs_wpss_is_user_admin()
	 *	@used by		WPSS_Utils::get_web_proxy()
	 *	@since			1.9.9.8.2
	 */
	static public function is_user_admin() {
		return rs_wpss_is_user_admin();
	}

	/**
	 *	Orders the array by key. Associative Arrays only.
	 *	@dependencies	...
	 *	@used by		WPSS_Utils::msort_array(), ...
	 *	@func_ver		WPSS.20190916.01
	 *	@since			WPSS 1.9.9.8.2, RSSD 1.0.5
	 */
	static public function ksort_array( $arr = array() ) {
		if( empty( $arr ) || !is_array( $arr ) || self::is_array_multi( $arr ) || !self::is_array_assoc( $arr ) ) { return $arr; }
		$tmp = $arr;
		ksort( $tmp, SORT_REGULAR | SORT_FLAG_CASE );
		$new = $tmp;
		return $new;
	}

	/**
	 *	If it does not exist, create the cache dir and copy default files.
	 *	@dependencies	WPSS_Utils::copy_dir_deep()
	 *	@used by		...
	 *	@since			1.9.xx
	 */

	/**
	 *	Create checksums for all plugin files.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.xx
	 */

	/**
	 *	Sorts the array, multidimensional.
	 *	Sorts Numeric arrays by Value, and Associative arrays by Key
	 *	@dependencies	WPSS_Utils::obj_to_arr(), WP_SpamShield::wp_memory_used(), WPSS_Utils::is_array_num(), WPSS_Utils::vsort_array(), WPSS_Utils::ksort_array()
	 *	@used by		...
	 *	@func_ver		RSSD.20191025.01
	 *	@since			WPSS 1.9.9.8.2, RSSD 1.0.4
	 */
	static public function msort_array( $arr = array(), $i = 0 ) {
		if( empty( $arr ) || !is_array( $arr ) ) { return $arr; }
		$tmp = $arr;
		++$i; $m = 5; /* $m = max */
		if( $i === $m || WP_SpamShield::wp_memory_used( FALSE, TRUE ) > 64 * MB_IN_BYTES ) {
			$new = array_multisort( $tmp );
		} else {
			if( self::is_array_num( $tmp ) ) { /* Numeric Arrays - Orders the array, by value. */
				$tmp = self::vsort_array( $tmp );
				foreach( (array) $tmp as $k => $v ) {
					if( is_array( $v ) || is_object( $v ) ) {
						if( is_object( $v ) ) { $v = self::obj_to_arr( $v ); }
						$tmp[$k] = self::msort_array( $v, $i );
					} else { $tmp[$k] = $v; }
				}
			} else { /* Associative Arrays - Orders the array, by key. */
				$tmp = self::ksort_array( $tmp );
				foreach( (array) $tmp as $k => $v ) {
					if( is_array( $v ) || is_object( $v ) ) {
						if( is_object( $v ) ) { $v = self::obj_to_arr( $v ); }
						$tmp[$k] = self::msort_array( $v, $i );
					} else { $tmp[$k] = $v; }
				}
			}
			$new = $tmp;
		}
		return $new;
	}

	/**
	 *	Convert Object to Multidimensional Associative Array
	 *	@dependencies	WPSS_PHP::json_encode()
	 *	@used by		...
	 *	@func_ver		WPSS.20190916.01
	 *	@since			WPSS 1.9.9.8.2, RSSD 1.0.4
	 */
	static public function obj_to_arr( $obj ) {
		if( empty( $obj ) || !is_object( $obj ) ) { return array(); }
		return (array) json_decode( WPSS_PHP::json_encode( $obj ), TRUE );
	}

	/**
	 *	Purge cached data / refresh the cache directory.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.xx
	 */

	/**
	 *	Set Crypto keys.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.xx
	 */

	/**
	 *	Sort an array by strlen of the values.
	 *	@dependencies	WPSS_Utils::strlen_cmp()
	 *	@used by		WPSS_Utils::copy_dir_deep()
	 *	@since			1.9.35
	 *	@param			array		$arr		Array to sort.
	 *	@param			string		$order		'dsc'|'asc' - Descending or Ascending. Defaults to descending.
	 */
	static public function sort_by_strlen( $arr, $order = 'dsc' ) {
		usort( $arr, array( __CLASS__, 'strlen_cmp' ) );
		if( 'asc' === $order ) { $arr = array_reverse( $arr ); }
		return $arr;
	}

	/**
	 *	Removes duplicates and empty values, then orders the array. Single-dimensional Numeric Arrays only.
	 *	@dependencies	WPSS_Utils::obj_to_arr(), WPSS_Utils::is_array_multi(), ...
	 *	@used by		...
	 *	@func_ver		WPSS.20190401.01
	 *	@since			WPSS 1.9.9.8.2, RSSD 1.0.4
	 */
	static public function sort_unique( $arr = array() ) {
		if( empty( $arr ) || !is_array( $arr ) ) { return $arr; }
		if( !self::is_array_num( $arr ) || self::is_array_multi( $arr ) ) { return $arr; }
		$tmp = array_filter( array_unique( $arr, SORT_REGULAR ) );
		sort( $tmp, SORT_REGULAR );
		return ( $new = array_values( $tmp ) );
	}

	/**
	 *	Store data in cache for a limited period of time.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.xx
	 *	@param			string		$slug		Slug of filename to be written.
	 *	@param			mixed		$data		Data to be cached.
	 *	@param			bool		$bak		If TRUE, make a backup file.
	 *	@param			bool		$cnf		If TRUE, make a config data file. Overrides `$bak`.
	 */

	/**
	 *	Store data in the WP-SpamShield config file. Wrapper for `WPSS_Utils::store_cache_data()`.
	 *	@dependencies	WPSS_Utils::store_cache_data()
	 *	@used by		...
	 *	@since			1.9.xx
	 */

	/**
	 *	Helper function for `WPSS_Utils::sort_by_strlen()` function.
	 *	@dependencies	rs_wpss_strlen()
	 *	@used by		WPSS_Utils::sort_by_strlen()
	 *	@since			1.9.35
	 */
	static public function strlen_cmp( $a, $b ) {
		return rs_wpss_strlen( $b ) - rs_wpss_strlen( $a );
	}

	/**
	 *	Check if all blocks of an IP exist within a string (IPv4 only)
	 *	IP comes in AA.BB.CC.DD format
	 *	@dependencies	WP_SpamShield::is_valid_ip(), WP_SpamShield::preg_match()
	 *	@used by		spammy_domain_chk()
	 *	@since			1.9.9.8.6
	 */
	static public function substr_ipv4_blocks( $ip, $str ) {
		if( empty( $ip ) || FALSE === strpos( $ip, '.' ) || !parent::is_valid_ip( $ip ) ) { return $ip; }
		$blocks = explode( '.', $ip ); $a = $blocks[0]; $b = $blocks[1]; $c = $blocks[2]; $d = $blocks[3];
		return
		(
			WP_SpamShield::preg_match( "~(^|[a-z]?[x\.\-][a-z]?)".$a."[a-z]?[x\.\-][a-z]?~i", $str )
			&&
			WP_SpamShield::preg_match( "~(^|[a-z]?[x\.\-][a-z]?)".$b."[a-z]?[x\.\-][a-z]?~i", $str )
			&&
			WP_SpamShield::preg_match( "~(^|[a-z]?[x\.\-][a-z]?)".$c."[a-z]?[x\.\-][a-z]?~i", $str )
			&&
			WP_SpamShield::preg_match( "~(^|[a-z]?[x\.\-][a-z]?)".$d."[a-z]?[x\.\-][a-z]?~i", $str )
		);
	}

	/**
	 *	Unset $_GET keys
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.35
	 */
	static public function unget( $keys = array(), $pref = '', $is_admin = FALSE, $page = NULL, $pagenow = NULL ) {
		if( empty( $keys ) || ( !is_string( $keys ) || FALSE === strpos( $keys, '|' ) && !is_array( $keys ) ) || empty( $_GET ) ) { return FALSE; }
		if( TRUE === $is_admin && ( !parent::is_admin() || ( !empty( $page ) && ( empty( $_GET['page'] ) || $page !== $_GET['page'] ) ) || ( !empty( $pagenow ) && ( empty( $GLOBALS['pagenow'] ) || $pagenow !== $GLOBALS['pagenow'] ) ) ) ) { return FALSE; }
		if( is_string( $keys ) ) { $keys = (array) explode( '|', $keys ); }
		$unset	= ( is_string( $keys ) ) ? (array) explode( '|', $keys ) : (array) $keys;
		foreach( (array) $unset as $i => $k ) { unset( $_GET[$pref.$k] ); }
		return TRUE;
	}

	/**
	 *	Unset $_POST keys
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.35
	 */
	static public function unpost( $keys = array(), $pref = '', $is_admin = FALSE, $page = NULL, $pagenow = NULL ) {
		if( empty( $keys ) || ( !is_string( $keys ) || FALSE === strpos( $keys, '|' ) && !is_array( $keys ) ) || 'POST' !== WPSS_REQUEST_METHOD || empty( $_POST ) ) { return FALSE; }
		if( TRUE === $is_admin && ( !parent::is_admin() || ( !empty( $page ) && ( empty( $_GET['page'] ) || $page !== $_GET['page'] ) ) || ( !empty( $pagenow ) && ( empty( $GLOBALS['pagenow'] ) || $pagenow !== $GLOBALS['pagenow'] ) ) ) ) { return FALSE; }
		if( is_string( $keys ) ) { $keys = (array) explode( '|', $keys ); }
		$unset	= ( is_string( $keys ) ) ? (array) explode( '|', $keys ) : (array) $keys;
		foreach( (array) $unset as $i => $k ) { unset( $_POST[$pref.$k] ); }
		return TRUE;
	}

	/**
	 *	Orders the array by value without removing duplicates. Single-dimensional Numeric Arrays only.
	 *	@dependencies	WPSS_Utils::is_array_multi(), WPSS_Utils::is_array_num()
	 *	@used by		...
	 *	@func_ver		WPSS.20190916.01
	 *	@since			WPSS 1.9.9.8.2, RSSD 1.0.5
	 */
	static public function vsort_array( $arr = array() ) {
		if( empty( $arr ) || !is_array( $arr ) || self::is_array_multi( $arr ) || !self::is_array_num( $arr ) ) { return $arr; }
		$tmp = $arr;
		sort( $tmp, SORT_REGULAR );
		return ( $new = array_values( $tmp ) );
	}

	/**
	 *	Archive a URL on WaybackMachine. Can be used to help prevent link rot.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			WPSS 1.9.38
	 */
	static public function wm_archive_url( $url, $get_url = FALSE ) {
		if( empty( $url ) || !is_string( $url ) ) { return FALSE; }
		$a = 'https://web.archive.org/save/'.$url;
		return ( TRUE === $get_url ) ? $a : parent::get_http_status( $a );
	}

	/**
	 *	Compare string2 against string1 and return a string containing the words in string2 that are not present in string1.
	 *	Optional: Return length of diff string instead of the content of the diff string.
	 *	@dependencies	WPSS_Func::lower(), rs_wpss_strlen(), ...
	 *	@used by		rs_wpss_comment_content_filter(), ...
	 *	@since			1.9.31
	 */
	static public function word_diff_strlen( $str1, $str2, $len = FALSE ) {
		if( empty( $str1 ) || empty( $str2 ) || !is_string( $str1 ) || !is_string( $str2 ) ) { return 0; }
		$str1		= WPSS_Func::lower( preg_replace( array( "~[^a-zA-Z0-9\ \-]~i" ), array( '' ), $str1 ) );
		$str2		= WPSS_Func::lower( preg_replace( array( "~[^a-zA-Z0-9\ \-]~i" ), array( '' ), $str2 ) );
		$arr1		= preg_split( "~\s~i", $str1 );
		$arr2		= preg_split( "~\s~i", $str2 );
		$arrdiff	= array_diff( $arr2, $arr1 );
		$strdiff	= implode( ' ', $arrdiff );
		$strdifflen	= rs_wpss_strlen( $strdiff );
		return ( TRUE === $len ) ? $strdifflen : $strdiff;
	}

	/**
	 *	Write data to wp-config.php, and create backup in cache.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.xx
	 *	@param			array		$data		Array of data to be cached.
	 *	@param			bool		$cnf_only	TRUE to write WP-SpamShield config file only.
	 *	@param			bool		$flush		TRUE to remove data from wp-config.php. (Use for uninstall.)
	 */

}



class WPSS_PHP extends WPSS_Utils {

	/**
	 *	WP-SpamShield PHP Function Replacements Class
	 *	Child class of WPSS_Utils
	 *	Replacements for certain PHP functions
	 *	Child classes: WPSS_Func, 
	 *	@since			1.9.9.8.2
	 */

	function __construct() {
		/**
		 *	Do nothing...for now
		 */
	}

	/**
	 *	Drop-in replacement for native PHP function `array_merge()` with improvements.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.35
	 *	@reference		https://secure.php.net/manual/en/function.array-merge.php
	 *	@param 			array		$arr1			Initial array to merge.
	 *	@param 			array		$arr2			Next array to merge.
	 *	@param 			array		$arr_multi		Array of arrays to merge. If necessary to merge more than 2 arrays, use this, and populate with arrays 3 to infinity.
	 *	@param 			bool		$overwrite		Whether to overwrite existing keys. (Defaults to TRUE, matching the behavior of native `array_merge()` function.)
	 */
	static public function array_merge( $arr1, $arr2 = array(), $arr_multi = array(), $overwrite = TRUE ) {
		$new = ( FALSE === $overwrite ) ? ( (array) $arr1 + (array) $arr2 ) : array_merge( (array) $arr1, (array) $arr2 );
		foreach( (array) $arr_multi as $i => $a ) {
			if( !is_array( $a ) ) { continue; }
			$new = self::array_merge( (array) $new, (array) $a, array(), $overwrite );
		}
		return $new;
	}

	/**
	 *	Drop-in replacement for native PHP function `array_merge()` with improvements.
	 *	Will not overwrite existing keys, unlike the behavior of native `array_merge()` function.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.35
	 *	@reference		https://secure.php.net/manual/en/function.array-merge.php
	 *	@param 			array		$arr1			Initial array to merge.
	 *	@param 			array		$arr2			Next array to merge.
	 *	@param 			array		$arr_multi		Array of arrays to merge. If necessary to merge more than 2 arrays, use this, and populate with arrays 3 to infinity.
	 */
	static public function array_union( $arr1, $arr2 = array(), $arr_multi = array() ) {
		return self::array_merge( (array) $arr1, (array) $arr2, (array) $arr_multi, FALSE );
	}

	/**
	 *	Drop-in replacement for native PHP function `base64_decode()`.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.16
	 *	@reference		https://secure.php.net/manual/en/function.base64-decode.php
	 */
	static public function base64_decode( $str, $strict = FALSE ) {
		return @base64_decode( $str, $strict );
	}

	/**
	 *	Drop-in replacement for native PHP function `base64_encode()`, with improvements.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.16
	 *	@reference		https://secure.php.net/manual/en/function.base64-encode.php
	 */
	static public function base64_encode( $str, $nopad = FALSE ) {
		$b64 = @base64_encode( $str );
		return ( ( TRUE === $nopad ) ? rtrim( $b64, '=' ) : $b64 );
	}

	/**
	 *	Drop-in replacement for native PHP function chmod()
	 *	Provides built-in error correction for $mode and additional security enhacement options.
	 *	$mode is input as octal integers to match standard file permissions (644, 755, etc.)
	 *	@dependencies	none
	 *	@used by		...
	 *	@since			1.9.9.8.8
	 *	@reference		https://secure.php.net/manual/en/function.chmod.php
	 *	@param 			string		$file			Path to the file.
	 *	@param 			numeric		$mode			The mode parameter consists of three octal number components specifying access restrictions.
	 *	@param 			bool		$check_exists	Check if file exists first.
	 *	@param 			bool		$quarantine		Quarantine the file.
	 *	@param 			numeric		$qmode			Set quarantine mode.
	 */
	static public function chmod( $file, $mode, $check_exists = FALSE, $quarantine = FALSE, $qmode = 310 ) {
		if( TRUE === $check_exists ) {
			@clearstatcache();
			if( ! @file_exists( $file ) ) { return; }
		}
		$mode	= ( TRUE === $quarantine ) ? $qmode : $mode;
		@chmod( $file, octdec( $mode ) );
	}

	/**
	 *	Drop-in replacement for native PHP function `copy()` with built-in error correction.
	 *	@dependencies	none
	 *	@used by		...
	 *	@since			1.9.35
	 *	@return			bool
	 *	@reference		https://secure.php.net/manual/en/function.copy.php
	 */
	static public function copy( $src_file, $dst_file ) {
		$dir = dirname( $dst_file ); @clearstatcache();
		if( ! @is_dir( $dir ) ) {
			wp_mkdir_p( $dir ); @clearstatcache();
		}
		if( @is_dir( $dir ) ) {
			if( !wp_is_writable( $dir ) ) { 
				self::chmod( $dir, 755 );
			}; @clearstatcache();
		}
		return @copy( $src_file, $dst_file );
	}

	/**
	 *	Drop-in replacement for native PHP function extension_loaded()
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.9.9.6
	 *	@reference		https://secure.php.net/manual/en/function.extension-loaded.php
	 *	@param			string		$extension 
	 */
	static public function extension_loaded( $extension ) {
		if( empty( $extension ) || !is_string( $extension ) ) { return FALSE; }
		if( function_exists( 'get_loaded_extensions' ) ) {
			$ext_loaded	= @get_loaded_extensions();
			$ext_loaded	= ( !empty( $ext_loaded ) && is_array( $ext_loaded ) ) ? $ext_loaded : array();
			return ( in_array( $extension, $ext_loaded ) );
		}
		return ( function_exists( 'extension_loaded' ) && (bool) @extension_loaded( $extension ) );
	}

	/**
	 *	Drop-in replacement for native PHP function `file_get_contents()` with built-in error correction.
	 *	@dependencies	none
	 *	@used by		...
	 *	@since			1.9.35
	 *	@return			string|bool:FALSE
	 *	@reference		https://secure.php.net/manual/en/function.file-get-contents.php
	 */
	static public function file_get_contents( $path ) {
		@clearstatcache();
		return ( @is_file( $path ) && ( $contents = @file_get_contents( $path ) ) ) ? $contents : '';
	}

	/**
	 *	Drop-in replacement for native PHP function `file_put_contents()` with built-in error correction.
	 *	@dependencies	none
	 *	@used by		...
	 *	@since			1.9.35
	 *	@return			numeric|bool:FALSE
	 *	@reference		https://secure.php.net/manual/en/function.file-put-contents.php
	 */
	static public function file_put_contents( $path, $data, $flags = 0 ) {
		if( empty( $path ) || !is_string( $path ) ) { return FALSE; }
		$path	= WP_SpamShield::normalize_ds( $path );
		$dir	= dirname( $path ); @clearstatcache();
		if( ! @is_dir( $dir ) ) {
			wp_mkdir_p( $dir ); @clearstatcache();
		}
		if( @is_dir( $dir ) ) {
			if( !wp_is_writable( $dir ) ) {
				self::chmod( $dir, 755 ); @clearstatcache();
			}
		}
		return @file_put_contents( $path, $data, $flags );
	}

	/**
	 *	Drop-in replacement for native PHP function fileperms()
	 *	Provides built-in error correction for $mode
	 *	@dependencies	none
	 *	@used by		...
	 *	@since			1.9.9.8.8
	 *	@return			numeric
	 *	@reference		https://secure.php.net/manual/en/function.fileperms.php
	 *	@reference		https://codex.wordpress.org/Changing_File_Permissions
	 */
	static public function fileperms( $path, $clear_cache = TRUE ) {
		if( FALSE !== $clear_cache ) { @clearstatcache(); }
		return decoct( @fileperms( $path ) & 0777 );
	}

	/**
	 *	Drop-in replacement for native PHP function `gettype()`.
	 *	Provides built-in error correction. Difference: Returns 'float' and 'null' instead of 'double' and 'NULL', respectively.
	 *	@dependencies	none
	 *	@used by		...
	 *	@since			1.9.35
	 *	@return			string
	 *	@reference		https://secure.php.net/manual/en/function.gettype.php
	 */
    static public function gettype( $var ) {
		$types = array( 'bool' => 'boolean', 'null', 'int' => 'integer', 'float', 'numeric', 'string', 'array', 'object', 'resource' );
		foreach( (array) $types as $k => $type ) { $func = ( 0 === strpos( $type, $k ) ) ? 'is_'.$k : 'is_'.$type; if( $func( $var ) ) { return $type; }; }; return 'unknown type';
    }

	/**
	 *	Use this function to find the matching array key(s) for a given value.
	 *	If `in_array()` is TRUE, this will return an array with all matching keys.
	 *	Uses 'in_array( $needle, $haystack, TRUE )' ($strict = TRUE) by default.
	 *	If $strict is FALSE, then it will allow numerical integers to be matched to strings.
	 *	If `in_array()` is FALSE, returns boolean FALSE.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.35
	 *	@reference		https://secure.php.net/manual/en/function.in-array.php
	 *	@param			string				$needle
	 *	@param			array				$haystack
	 *	@param			bool				$strict
	 *	@return			bool|array
	 */
	static public function get_array_keys( $needle, $haystack, $strict = TRUE ) {
		if( empty( $haystack ) || !is_array( $haystack ) || empty( $needle ) || !is_string( $needle ) ) { return FALSE; }
		if( in_array( $needle, $haystack, ( $strict = ( FALSE !== $strict ) ) ) ) {
			$haystack_flip = array_flip( $haystack ); $haystack_flip_count = count( $haystack_flip ); $haystack_count = count( $haystack ); $keys = array();
			if( $haystack_flip_count === $haystack_count ) { /* Single key match */
				$keys[] = (string) $haystack_flip[$needle];
			} else { /* Multiple key matches */
				foreach( (array) $haystack as $k => $v ) {
					if( empty( $v ) || ( !is_string( $v ) && !is_int( $v ) ) || $v != $needle || ( TRUE === $strict && $v !== $needle ) ) { continue; }
					$keys[] = $v;
				}
			}
		}
		return ( !empty( $keys ) && is_array( $keys ) ) ? $keys : FALSE;
	}

	/**
	 *	Use this function instead of json_encode() for compatibility, especially with non-UTF-8 data.
	 *	wp_json_encode() was added in WP ver 4.1
	 *	@dependencies	WP_SpamShield::is_wp_ver()
	 *	@used by		...
	 *	@since			1.9.8.4 as rs_wpss_json_encode()
	 *	@moved			1.9.9.8.2 to WPSS_PHP class
	 *	@reference		https://secure.php.net/manual/en/function.json-encode.php
	 *	@reference		https://developer.wordpress.org/reference/functions/wp_json_encode/
	 */
	static public function json_encode( $data, $options = 0, $depth = 512 ) {
		return ( function_exists( 'wp_json_encode' ) && WP_SpamShield::is_wp_ver( '4.1' ) ) ? wp_json_encode( $data, $options, $depth ) : json_encode( $data, $options );
	}

	/**
	 *	Drop-in replacement for native PHP function `parse_str()` with improvements.
	 *	@dependencies	WPSS_PHP::is_parsable()
	 *	@used by		rs_wpss_get_query_args(), WPSS_Security::check_admin_sec()
	 *	@since			1.9.31
	 *	@return			array|mixed
	 *	@reference		https://secure.php.net/manual/en/function.parse-str.php
	 */
	static public function parse_str( $str ) {
		if( !parent::is_parsable( $str ) ) { return $str; }
		parse_str( $str, $arr );
		return $arr;
	}

	/**
	 *	Drop-in replacement for native PHP function `print_r()` with improvements.
	 *	This version compresses the output to save space and take up fewer lines.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.xx
	 */

	/**
	 *	Drop-in replacement for native PHP function `posix_getpwuid()` with built-in error correction.
	 *	Required for certain web hosts that disable this function: @WPEngine
	 *	@dependencies	none
	 *	@used by		...
	 *	@since			1.9.42
	 *	@return			string
	 *	@reference		https://secure.php.net/manual/en/function.posix-getpwuid.php
	 */
	static public function posix_getpwuid( $uid ) {
		return ( function_exists( 'posix_getpwuid' ) && !empty( $uid ) ) ? @posix_getpwuid( $uid ) : '';
	}

	/**
	 *	Drop-in replacement for native PHP function `posix_getgrgid()` with built-in error correction.
	 *	Required for certain web hosts that disable this function: ...
	 *	@dependencies	none
	 *	@used by		...
	 *	@since			1.9.42
	 *	@return			string
	 *	@reference		https://secure.php.net/manual/en/function.posix-getgrgid.php
	 */
	static public function posix_getgrgid( $gid ) {
		return ( function_exists( 'posix_getgrgid' ) && !empty( $gid ) ) ? @posix_getgrgid( $gid ) : '';
	}

	/**
	 *	Drop-in replacement for PHP function `rmdir()`, with improvements.
	 *	Has error correction built-in and recursive scanning/deletion.
	 *	Unlike, `rmdir()`, directories do not have to be empty. This removes all subdirectories and files within the given path.
	 *	@dependencies	WPSS_Utils::sort_unique(), WPSS_Utils::array_flatten(), WPSS_PHP::scandir_deep(), WPSS_PHP::chmod(), ...
	 *	@used by		...
	 *	@since			1.9.xx
	 *	@return			bool
	 *	@reference		https://secure.php.net/manual/en/function.rmdir.php
	 *	@param			string		$dir		Directory path
	 */

	/**
	 *	Drop-in replacement for PHP function `scandir()`, with improvements.
	 *	Has sanitation and error correction built-in, recursive scanning, memory leak prevention, and removes dot files.
	 *	@dependencies	...
	 *	@used by		...
	 *	@since			1.9.xx
	 *	@reference		https://secure.php.net/manual/en/function.scandir.php
	 *	@param			string		$dir		Directory path
	 *	@param			bool		$deep		If TRUE, do a deep scan (recursive).
	 *	@param			bool		$getdat		If TRUE, get detailed file data as well.
	 *	@param			integer		$depth		Number of levels to recurse. Only if $deep is TRUE. 0 means no limit.
	 *	@param			integer		$z			Number of iterations.
	 */

	/**
	 *	Drop-in replacement for native PHP function `setcookie()`.
	 *	@dependencies	WP_SpamShield::is_https()
	 *	@used by		...
	 *	@since			1.9.16
	 *	@reference		https://secure.php.net/manual/en/function.setcookie.php
	 *	@param 			string		$name			The name of the cookie.
	 *	@param 			string		$value			The value of the cookie.
	 *	@param 			int			$expire			The time the cookie expires. This is a Unix timestamp so is in number of seconds since the epoch.
	 *	@param 			string		$path			The path on the server in which the cookie will be available on.
	 *	@param 			string		$domain			The (sub)domain that the cookie is available to.
	 *	@param 			bool		$secure			Indicates that the cookie should only be transmitted over a secure HTTPS connection from the client.
	 *	@param 			bool		$httponly		When TRUE the cookie will be made accessible only through the HTTP protocol.
	 *	@param 			bool		$check_if_set	When TRUE, only set the cookie if not already set.
	 *	@return			void
	 */
	static public function setcookie( $name, $value = '', $expire = 0, $path = '', $domain = '', $secure = FALSE, $httponly = FALSE, $check_if_set = FALSE ) {
		if( headers_sent() ) { return; }
		if( FALSE === $check_if_set || !isset( $_COOKIE[$name] ) ) {
			@setcookie( $name, $value, $expire, $path, $domain, ( $secure && WP_SpamShield::is_https() ), $httponly );
		}
	}

	/**
	 *	@alias of 		rs_wpss_substr_count()
	 *	@used by		...
	 *	@since			1.9.9.8.6
	 */
	static public function substr_count( $haystack, $needle, $offset = 0, $length = NULL ) {
		return rs_wpss_substr_count( $haystack, $needle, $offset, $length );
	}

	/**
	 *	Array version of native PHP function `strpos()`.
	 *	Can be used as drop in replacement for basic match functionality. Built-in error correction.
	 *	Can process an array of needles to check in haystack. For a short list, this is more efficient than using PCRE Regex ( `preg_match()` etc ).
	 *	@dependencies	WPSS_Func::lower(), ...
	 *	@used by		...
	 *	@since			1.9.14
	 *	@reference		https://secure.php.net/manual/en/function.strpos.php
	 *	@param			string		$haystack 
	 *	@param			mixed		$needle 
	 *	@param			bool		$nocase		If TRUE, case-insensitive. Defaults to case-sensitive.
	 *	@param			int			$offset 
	 */
	static public function strpos_arr( $haystack, $needle, $nocase = FALSE, $offset = 0 ) {
		$pos = FALSE;
		if( !is_string( $haystack ) || ( !is_string( $needle ) && !is_array( $needle ) ) ) { return FALSE; }
		$needles = ( is_string( $needle ) ) ? array( $needle ) : (array) $needle;
		if( TRUE === $nocase ) { $haystack = WPSS_Func::lower( $haystack ); }
		foreach( (array) $needles as $i => $needle ) {
			if( TRUE === $nocase ) { $needle = WPSS_Func::lower( $needle ); }
			if( $needle === $haystack ) { return 0; }
			$pos = strpos( $haystack, $needle, $offset );
			if( FALSE !== $pos ) { return $pos; }
		}
		return $pos;
	}

	/**
	 *	Determine if $needle occurs at the end of the $haystack (right side).
	 *	Drop-in replacement for native PHP function `strpos()`.
	 *	@dependencies	none
	 *	@used by		...
	 *	@since			1.9.32
	 *	@return			bool
	 *	@reference		https://secure.php.net/manual/en/function.strpos.php
	 */
	static public function strpos_end( $haystack, $needle ) {
		return ( strpos( $haystack, $needle ) === ( strlen( $haystack ) - strlen( $needle ) ) );
	}




	/**
	 *	Deprecata
	 */

	static public function in_array( $needle, $haystack ) {
		_deprecated_function( __METHOD__, '1.9.35', 'in_array()' );
		return in_array( $needle, $haystack );
	}

}



class WPSS_Func extends WPSS_PHP {

	/**
	 *	WP-SpamShield Utility Functions Alias Class
	 *	Aliases of PHP function replacements
	 *	Child class of WPSS_PHP; Grandchild class of WPSS_Utils
	 *	Child classes: ... 
	 *	@since	1.9.9.8.2
	 */

	function __construct() {
		/**
		 *	Do nothing...for now
		 */
	}

	/**
	 *	Alias of WP_SpamShield::base64_decode()
	 *	@dependencies	WP_SpamShield::base64_decode()
	 *	@used by		...
	 *	@since			1.9.16
	 *	@reference		https://secure.php.net/manual/en/function.base64-decode.php
	 */
	static public function ecto( $str, $strict = FALSE ) {
		return parent::base64_decode( $str, $strict );
	}

	/**
	 *	Alias of WP_SpamShield::base64_encode()
	 *	@dependencies	WP_SpamShield::base64_encode()
	 *	@used by		...
	 *	@since			1.9.16
	 *	@reference		https://secure.php.net/manual/en/function.base64-encode.php
	 */
	static public function endo( $str, $nopad = FALSE ) {
		return parent::base64_encode( $str, $nopad );
	}

	/**
	 *	Alias of WP_SpamShield::casetrans( 'lower', $str )
	 *	Replaces PHP function strtolower()
	 *	@dependencies	WP_SpamShield::casetrans()
	 *	@used by		...
	 *	@usage			WPSS_Func::lower( $str )
	 *	@since			1.9.9.8.2
	 */
	static public function lower( $str ) {
		return WP_SpamShield::casetrans( 'lower', $str );
	}

	/**
	 *	Alias of WP_SpamShield::casetrans( 'upper', $str )
	 *	Replaces PHP function strtoupper()
	 *	@dependencies	WP_SpamShield::casetrans()
	 *	@used by		...
	 *	@usage			WPSS_Func::upper( $str )
	 *	@since			1.9.9.8.2
	 */
	static public function upper( $str ) {
		return WP_SpamShield::casetrans( 'upper', $str );
	}

	/**
	 *	Alias of WP_SpamShield::casetrans( 'ucfirst', $str )
	 *	Replaces PHP function ucfirst()
	 *	@dependencies	WP_SpamShield::casetrans()
	 *	@used by		...
	 *	@usage			WPSS_Func::ucfirst( $str )
	 *	@since			1.9.9.8.2
	 */
	static public function ucfirst( $str ) {
		return WP_SpamShield::casetrans( 'ucfirst', $str );
	}

	/**
	 *	Alias of WP_SpamShield::casetrans( 'ucwords', $str )
	 *	Replaces PHP function ucwords()
	 *	@dependencies	WP_SpamShield::casetrans()
	 *	@used by		...
	 *	@usage			WPSS_Func::ucwords( $str )
	 *	@since			1.9.9.8.2
	 */
	static public function ucwords( $str ) {
		return WP_SpamShield::casetrans( 'ucwords', $str );
	}



	/**
	 *	Deprecata
	 */

	static public function b64de( $str, $strict = FALSE ) {
		_deprecated_function( __METHOD__, '1.9.42', 'WPSS_Func::ecto()' );
		return WPSS_Func::ecto( $str, $strict = FALSE );
	}

	static public function b64en( $str ) {
		_deprecated_function( __METHOD__, '1.9.42', 'WPSS_Func::endo()' );
		return WPSS_Func::endo( $str, $strict = FALSE );
	}

	static public function casetrans( $type, $str ) {
		_deprecated_function( __METHOD__, '1.9.9.9.4', 'WP_SpamShield::casetrans()' );
		return WP_SpamShield::casetrans( $type, $str );
	}

	static public function in_array( $needle, $haystack ) {
		_deprecated_function( __METHOD__, '1.9.35', 'in_array()' );
		return in_array( $needle, $haystack );
	}

}

