Location: PHPKode > scripts > NuCaptcha (PHP) > nucaptcha-client-php-1.0.12882/nucaptcha-client-php-1.0.12882/php/leapclusterpicker.php
<?php
/**
 * @package   NuCaptcha PHP clientlib
 * @author    <hide@address.com> Leap Marketing Technologies Inc
 * @license   LGPL License 2.1 (see included license.txt)
 * @link      http://www.nucaptcha.com/api/php
 */

/**
 * Pick a cluster to use.
 *
 * @see http://intra.leapmarketing.com/confluence/display/TD/Cluster+Selection+Process
 * @package LeapClient
 */
class lmClusterPicker
{
    private function __construct() {}
    
    /**
     * Cache the DNS record to prevent multiple lookups
     * @var Array
     */
    private static $sDNSCache = Array();
    
    /**
     * Cache the cluster so it's consistent across calls
     * @var string
     */
    private static $sCluster = false;
	
	/**
	 * suffix to add to URLs that are generated. Gets set from clusterRecord
	 *
	 * @var string
	 */
	private static $sDomain = false;
    
    /**
     * Pick a cluster. First looks for an override in the config file for a
     * forceCluster, then a clusterRecord, then does a DNS lookup
     *
     * @return string
     */
    public static function PickCluster ()
    {		
		// perform the lookup
		if(false === self::$sCluster)
		{
			$clusterRecord = Leap::getClusterRecord();
		
			// Assumes only the last two pieces.. clusters.nucaptcha.com
			// because nucaptcha.com. clusters.deptest.leapmarketing.com
			// becomes leapmarketing.com. I suspect this will change in the
			// future..
			$matches = Array();
			
			if(0 == preg_match('/\.([^\.]+\.[^\.]+)$/', $clusterRecord, $matches))
			{
				// last ditch effort -- assume nucaptcha
				trigger_error("Could not parse clusterRecord $clusterRecord. Defaulting to nucaptcha.com", E_USER_WARNING);
				self::$sDomain = 'nucaptcha.com';
			}
			else
			{
				self::$sDomain = $matches[1];
			}
						
			$result = self::GetDNS($clusterRecord);
			
			// parse the values
			$clusters = Array();
				
			foreach($result as $dnsrecord)
			{
				$clusters = array_merge($clusters, self::ParseRecord($dnsrecord['txt']));
			}
				
			// no clusters found!
			if(sizeof($clusters) === 0)
			{
				return 'default';
			}
			
			// pick a cluster at random
			self::$sCluster = $clusters[rand(0, sizeof($clusters)-1)];
		}
	
		return self::$sCluster;
    }
    
    /**
     * pull the cluster record from cache or DNS
     *
     * @param string $clusterRecord
     * @return array
     */
    private static function GetDNS ($clusterRecord)
    {
		if(true === array_key_exists($clusterRecord, self::$sDNSCache))
		{
			if(time() > self::$sDNSCache[$clusterRecord]['expires'])
			{
				return self::$sDNSCache[$clusterRecord]['record'];
			}
		}

		// forced a token server, use the old method.
		if(false === lmHelper::isDnsGetRecordSupported())
		{
			throw new Exception("dns_get_record() is not supported on this platform.");
		}

		$result = dns_get_record($clusterRecord, DNS_TXT);
		
		if(sizeof($result) == 0)
		{
			throw new LeapException('Failed DNS lookup for '. $clusterRecord . '.',	LMSC_DNSERROR);
		}
		
		self::$sDNSCache[$clusterRecord]['record'] = $result;
		self::$sDNSCache[$clusterRecord]['expires'] = time() + $result[0]['ttl'];
		
		return $result;
    }
    
    /**
     * parse a TXT record. Returns Array($name * $weight)
     *
     * FIXME this weighting is wrong -- it doesn't match the description at
     * http://intra.leapmarketing.com/confluence/display/TD/Cluster+Selection+Process
     *
     * On failure, returns an empty array
     *
     * @param string $record
     * @return array ('record', 'record', etc) based on weight
     */
    protected static function ParseRecord ($record)
    {
		$results = explode(' ', $record, 2);
		$weight  = 1;
		$matches = Array();
		
		
		// weight is correct
		if(0 == sizeof($results))
		{
			throw new LeapException("Cluster record could not be split.", LMSC_DNSERROR);
		}
		elseif('' == $results[0])
		{
			throw new LeapException("Cluster record is empty", LMSC_DNSERROR);
		}
		elseif(1 == sizeof($results))
		{
			// use default weight -- record didn't parse correctly.
			// very likely things are super corrupted, but give it a go
		}
		elseif(true === ctype_digit($results[1]))
		{
			$weight = $results[1];
		}
		// weight contains a number
		elseif(1 == preg_match('/(\d+)/', $results[1], $matches))
		{
			$weight = $matches[0];	
		}
		// otherwise, weight remains 1
		
		$weighted = Array();
		
		for($i = 0; $i < $weight; $i++)
		{
			$weighted[] = $results[0];
		}
		
		return $weighted;
    }
    
    /**
     * Get the token server for this configuration.
     *
     * @return string URL for token server
     */
    public static function GetTokenServer ()
    {
		return self::GetServer('forceTokenServer', 'token');
    }
    
    /**
     * Get the data server for this configuration.
     *
     * @return string URL for data server
     */
    public static function GetDataServer ()
    {
		return self::GetServer('forceDataServer', 'data');
    }
    
    /**
     * Get the validate server for this configuration.
     *
     * @return string URL for validate server
     */
    public static function GetValidateServer ()
    {
		return self::GetServer('forceValidateServer', 'validate');
    }
    
    /**
     * Get the resource server URL.
     *
     * @return string URL for resources
     */
    public static function GetResourceServer ()
    {		
		$resourcerecord = sprintf('resources.%s.' . self::$sDomain, self::PickCluster());

		// forced a token server, use the old method.
		if(false === lmHelper::isDnsGetRecordSupported())
		{
			throw new Exception("dns_get_record() is not supported on this platform.");
		}

		$result = dns_get_record($resourcerecord, DNS_TXT);
		
		if(sizeof($result) === 0)
		{
			trigger_error("No TXT record found for $resourcerecord.", E_USER_WARNING);
			// FIXME probably need a default here. It currently returns the resourcerecord -- it may work?
			// but no version number
			return "http://$resourcerecord/";
		}
		
		return $result[0]['txt'];
    }
    
    /**
     * Generic function for getting a server URL
     *
     * @param string $configname
     * @param string $prefix
     * @return string
     */
    private static function GetServer ($configName, $prefix)
    {
		/*try
		{
			$server = lmDefaultConfig::GetGlobal($configname);
			
			return $server;
		}
		catch (Exception $e) {}
		*/
	
		// most of the old force* records aren't used any more. Instead,
		// we do this:
		if('forceTokenServer' == $configName)
		{
			if(false != Leap::getForceTokenServer())
			{
				return Leap::getForceTokenServer();
			}
		}
		
		return sprintf('http://%s.%s.%s/', 
			$prefix,
			self::PickCluster(),
			self::$sDomain
		);
    }
    
    /**
     * If you're code is persistent, this method will reset the cluster
     */
    public function ClearCluster()
    {
		self::$sCluster = false;
    }
}
Return current item: NuCaptcha (PHP)