Location: PHPKode > scripts > PADL (PHP Application Distribution License System) > shared/class.license.lib.php
<?php

	/**
	* Project:		Distrubution License Class
	* File:			class.license.lib.php
	*
	* Copyright (C) 2005 Oliver Lillie
	* 
	* This program is free software; you can redistribute it and/or modify it 
	* under the terms of the GNU General Public License as published by  the Free 
	* Software Foundation; either version 2 of the License, or (at your option) 
	* any later version.
	*
	* This program is distributed in the hope that it will be useful, but 
	* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
	* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
	* for more details.
	*
	* You should have received a copy of the GNU General Public License along 
	* with this program; if not, write to the Free Software Foundation, Inc., 
	* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA	
	*
	* @link http://www.buggedcom.co.uk/
	* @link http://www.phpclasses.org/browse/package/2298.html
	* @author Oliver Lillie, buggedcom <publicmail at buggedcom dot co dot uk>
	* @version 0.1
	* @history---------------------------------------------
	* see CHANGELOG
	*/

	class padl {
	
		/**
		* hash key 1 used to encrypt the generate key data.
		* hash key 2 used to encrypt the request data
		* hash key 3 used to encrypt the dial home data
		* NOTE1 : there are three different hash keys for the three different operations
		* NOTE2 : these hash key's are for use by both mcrypt and alternate cryptions
		* 		  and although mcrypts keys are typically short they should be kept long
		*		  for the sake of the other functions
		*
		* @var string
		* @var string
		* @var string
		*/
		 var $HASH_KEY1 	= 'YmUzYWM2sNGU24NbA363zA7IDSDFGDFGB5aVi35BDFGQ3YNO36ycDFGAATq4sYmSFVDFGDFGps7XDYEzGDDw96OnMW3kjCFJ7M+UV2kHe1WTTEcM09UMHHT';
		 var $HASH_KEY2 	= '80dSbqylf4Cu5e5OYdAoAVkzpRDWAt7J1Vp27sYDU52ZBJprdRL1KE0il8KQXuKCK3sdA51P9w8U60wohX2gdmBu7uVhjxbS8g4y874Ht8L12W54Q6T4R4a';
		 var $HASH_KEY3 	= 'ant9pbc3OK28Li36Mi4d3fsWJ4tQSN4a9Z2qa8W66qR7ctFbljsOc9J4wa2Bh6j8KB3vbEXB18i6gfbE0yHS0ZXQCceIlG7jwzDmN7YT06mVwcM9z0vy62T';
		 
		/**
		* You may not want to use mcrypt even if your system has it installed
		* make this false to use a regular encryption method
		*
		* @var boolean
		*/
		var $USE_MCRYPT	= true;

		/**
		* The algorythm to be used by mcrypt
		*
		* @var string
		*/
		var $ALGORITHM		= 'blowfish';

		/**
		* use time binding vars inited.
		*/
		var $USE_TIME;
		
		/**
		* time checking start period difference allowance ie if the user has slightly different time 
		* setting on their server make an allowance for the diff period. carefull to not make it too 
		* much otherwise they could just reset their server to a time period before the license expires.
		*
		* @var number (seconds)
		*/
		var $START_DIF		= 129600;  
		
		/**
		* id 1 used to validate license keys
		* id 2 used to validate license key requests
		* id 2 used to validate dial home data
		*
		* @var string
		* @var string
		* @var string
		*/
		# id to check for to validate source
		var $ID1			= 'nSpkAHRiFfM2hE588eB';
		var $ID2			= 'NWCy0s0JpGubCVKlkkK';
		var $ID3			= 'G95ZP2uS782cFey9x5A';

		/**
		* begining and end strings
		*
		* @var strings
		*/
		var $BEGIN1 		= 'BEGIN LICENSE KEY';
		var $END1			= 'END LICENSE KEY';

		/**
		* wrap key settings
		*
		* @var number
		* @var string
		* @var string
		*/
		var $_WRAPTO		= 80;
		var $_PAD			= "-";
		
		/**
		* init the linebreak var
		*/
		var $_LINEBREAK;
		
		/**
		* dial home return query deliminators
		*
		* @var string
		* @var string
		*/
		var $BEGIN2	 	= '_DATA{';
		var $END2	 		= '}DATA_';
			
		/**
		* init the key data array.
		*
		* @var array
		*/
		var $_DATA			= array();

		/**
		* use server binding vars inited.
		*/
		var $USE_SERVER;
		var $_SERV;
		var $_MAC;
		var $ALLOW_LOCAL;
		var $_SERVER_INFO = array();
		
		/**
		* this is the number of required server stats for the key generation to be successfull
		* if the server can't produce this number of details then the key fails to be generated
		* you can set it to however many you wish, the max is 5
		*
		* @var number
		*/
		var $REQUIRED_URIS	= 2;

		/**
		* the date string for human readable format
		*
		* @var string
		*/
		var $DATE_STRING	= 'd/M/Y H:i:s';
		
		/**
		* Constructor
		*
		* @access private 
		**/
		function padl()
		{
			# check to see if the class has been secured
			$this->_check_secure();
		}

		/**
		* init
		*
		* init the license class
		*
		* @access public 
		* @param $use_mcrypt boolean Determines if mcrypt encryption is used or not (defaults to true, 
		*					 however if mcrypt is not available, it is set to false) 
		* @param $use_time boolean Sets if time binding should be used in the key (defaults to true) 
		* @param $use_server boolean Sets if server binding should be used in the key (defaults to true) 
		* @param $allow_local boolean Sets if server binding is in use then localhost servers are valid (defaults to false) 
		**/
		function init($use_mcrypt=true, $use_time=true, $use_server=true, $allow_local=false)
		{
			# check to see if the class has been secured
			$this->_check_secure();
			$this->USE_MCRYPT			= ($use_mcrypt && function_exists('mcrypt_generic'));
			$this->USE_TIME			= $use_time;
			$this->ALLOW_LOCAL			= $allow_local;
			$this->USE_SERVER			= $use_server;
			$this->_LINEBREAK			= $this->_get_os_linebreak();
		}
		
		/**
		* _get_os_linebreak
		*
		* get's the os linebreak
		*
		* @access private 
		* @param $true_val boolean If the true value is needed for writing files, make true
		*							defaults to false
  		* @return string Returns the os linebreak
		**/
		function _get_os_linebreak($true_val=false)
		{
			$os = strtolower(PHP_OS);
			switch($os)
			{
				# not sure if the string is correct for FreeBSD
				# not tested
				case 'freebsd' : 
				# not sure if the string is correct for NetBSD
				# not tested
				case 'netbsd' : 
				# not sure if the string is correct for Solaris
				# not tested
				case 'solaris' : 
				# not sure if the string is correct for SunOS
				# not tested
				case 'sunos' : 
				# linux variation
				# tested on server
				case 'linux' : 
					$nl = "\n";
					break;
				# darwin is mac os x
				# tested only on the client os
				case 'darwin' : 
					# note os x has \r line returns however it appears that the ifcofig
					# file used to source much data uses \n. let me know if this is
					# just my setup and i will attempt to fix.
					if($true_val) $nl = "\r";
					else $nl = "\n";
					break;
				# defaults to a win system format;
				default :
					$nl = "\r\n";
			}
			return $nl;
		}
		
		/**
		* _post_data
		*
		* Posts data to and recieves data from dial home server. Returned info
		* contains the dial home validation result
		*
		* @access private 
		* @param $host string Host name of the server to be contacted
		* @param $path string Path of the script for the data to be sent to
		* @param $query_array array Array that contains the license key info to be validated
		* @param $port number Port Number to send the data through
  		* @return array Result of the dialhome validation
  		* @return string - SOCKET_FAILED will be returned if it was not possible to open a socket to the home server
		**/
		function _post_data($host, $path, $query_array, $port=80)
		{
			# generate the post query info
			$query 	 = 'POSTDATA='.$this->_encrypt($query_array, 'HOMEKEY');
			$query 	 .= '&MCRYPT='.$this->USE_MCRYPT;
			# init the return string
			$return  = '';
			
			# generate the post headers
			$post  	 = "POST $path HTTP/1.1\r\n";
			$post 	.= "Host: $host\r\n";
			$post 	.= "Content-type: application/x-www-form-urlencoded\r\n";
			$post 	.= "Content-length: ".strlen($query)."\r\n";
			$post 	.= "Connection: close\r\n";
			$post 	.= "\r\n";
			$post 	.= $query;

			# open a socket
			$header = @fsockopen($host, $port);
			if(!$header)
			{
				# if the socket fails return failed
				return array('RESULT'=>'SOCKET_FAILED');
			}
			@fputs($header, $post);
			# read the returned data
			while (!@feof($header))
			{
				$return .= @fgets($header, 1024);
			}
			fclose($header);
			
			# seperate out the data using the delims
			$leftpos = strpos($return, $this->BEGIN2)+strlen($this->BEGIN2);
			$rightpos = strpos($return, $this->END2)-$leftpos;

			#trace($return);
			
			# decrypt and return the data
			return $this->_decrypt(substr($return, $leftpos, $rightpos), 'HOMEKEY');
		}

		/**
		* _compare_domain_ip
		*
		* uses the supplied domain in the key and runs a check against the collected
		* ip addresses. If there are matching ips it returns true as the domain
		* and ip address match up
		*
		* @access private 
  		* @return boolean
		**/
		function _compare_domain_ip($domain, $ips=false)
		{
			# if no ips are supplied get the ip addresses for the server
			if(!$ips) $ips = $this->_get_ip_address();
			# get the domain ip list
			$domain_ips = gethostbynamel($domain);
			# loop through the collected ip's searching for matches against the domain ips
			if(is_array($domain_ips) && count($domain_ips) > 0)
			{
				foreach($domain_ips as $ip)
				{
					if(in_array($ip, $ips)) return true;
				}
			}
			return false;
		}

		/**
		* _pad
		*
		* pad out the begin and end seperators
		*
		* @access private 
		* @param $str string The string to be padded
  		* @return string Returns the padded string
		**/
		function _pad($str)
		{
			$str_len 	= strlen($str);
			$spaces 	= ($this->_WRAPTO-$str_len)/2;
			$str1 = '';
			for($i=0; $i<$spaces; $i++)
			{
				$str1 = $str1.$this->_PAD;
			}
			if($spaces/2 != round($spaces/2))
			{
				$str = substr($str1, 0, strlen($str1)-1).$str;
			}
			else
			{
				$str = $str1.$str;
			}
			$str = $str.$str1;
			return $str;
		}
		
		/**
		* _get_key
		*
		* gets the hash key for the current encryption
		*
		* @access private 
		* @param $key_type string The license key type being produced
  		* @return string Returns the hash key
		**/
		function _get_key($key_type)
		{
			switch($key_type)
			{
				case 'KEY' :
					return $this->HASH_KEY1;
				case 'REQUESTKEY' :
					return $this->HASH_KEY2;
				case 'HOMEKEY' :
					return $this->HASH_KEY3;
				default :
			}
		}

		/**
		* _get_begin
		*
		* gets the begining license key seperator text
		*
		* @access private 
		* @param $key_type string The license key type being produced
  		* @return string Returns the begining string
		**/
		function _get_begin($key_type)
		{
			switch($key_type)
			{
				case 'KEY' :
					return $this->BEGIN1;
				case 'REQUESTKEY' :
					return $this->BEGIN2;
				case 'HOMEKEY' :
					return '';
			}
		}
		
		/**
		* _get_end
		*
		* gets the ending license key seperator text
		*
		* @access private 
		* @param $key_type string The license key type being produced
  		* @return string Returns the ending string
		**/
		function _get_end($key_type)
		{
			switch($key_type)
			{
				case 'KEY' :
					return $this->END1;
				case 'REQUESTKEY' :
					return $this->_END2;
				case 'HOMEKEY' :
					return '';
			}
		}
		
		/**
		* _generate_random_string
		*
		* generates a random string
		*
		* @access private 
		* @param $length number The length of the random string
		* @param $seeds string The string to pluck the characters from
  		* @return string Returns random string
		**/
		function _generate_random_string($length=10, $seeds='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789')
		{
			$str = '';
			$seeds_count = strlen($seeds);
		
			list($usec, $sec) = explode(' ', microtime());
			$seed = (float) $sec + ((float) $usec * 100000);
			mt_srand($seed);
		
			for ($i = 0; $length > $i; $i++) {
				$str .= $seeds{mt_rand(0, $seeds_count - 1)};
			}
			return $str;
		}
		
		/**
		* _encrypt
		*
		* encrypts the key
		*
		* @access private 
		* @param $src_array array The data array that contains the key data
  		* @return string Returns the encrypted string
		**/
		function _encrypt($src_array, $key_type='KEY')
		{
			# check to see if the class has been secured
			$this->_check_secure();
			
			$rand_add_on = $this->_generate_random_string(3);
			# get the key
			$key 	= $this->_get_key($key_type);
			$key 	= $rand_add_on . $key;
			
			# check to see if mycrypt exists
			if($this->USE_MCRYPT)
			{
				# openup mcrypt
				$td 	= mcrypt_module_open($this->ALGORITHM, '', 'ecb', '');
				$iv 	= mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
				# process the key
				$key 	= substr($key, 0, mcrypt_enc_get_key_size($td));
				# init mcrypt
				mcrypt_generic_init($td, $key, $iv);
				
				# encrypt data
				# double base64 gets makes all the characters alpha numeric 
				# and gets rig of the special characters
				$crypt 	= mcrypt_generic($td, serialize($src_array));
			
				# shutdown mcrypt
				mcrypt_generic_deinit($td);
				mcrypt_module_close($td);
			}
			else
			{
				# if mcrypt doesn't exist use regular encryption method
				# init the vars
				$crypt = '';
				$str = serialize($src_array);
				
				# loop through the str and encrypt it
				for($i=1; $i<=strlen($str); $i++)
				{
					$char 		= substr($str, $i-1, 1);
					$keychar 	= substr($key, ($i % strlen($key))-1, 1);
					$char 		= chr(ord($char)+ord($keychar));
					$crypt		.= $char;
				}
				
			}
			# return the key
			return $rand_add_on.base64_encode(base64_encode(trim($crypt)));
		}
		
		/**
		* _decrypt
		*
		* decrypts the key
		*
		* @access private 
		* @param $enc_string string The key string that contains the data
  		* @return array Returns decrypted array
		**/
		function _decrypt($str, $key_type='KEY')
		{
			# check to see if the class has been secured
			$this->_check_secure();
			
			$rand_add_on = substr($str, 0, 3);
			$str = base64_decode(base64_decode(substr($str, 3)));
			# get the key
			$key 	= $rand_add_on . $this->_get_key($key_type);
			
			# check to see if mycrypt exists
			if($this->USE_MCRYPT)
			{
				# openup mcrypt
				$td 	= mcrypt_module_open($this->ALGORITHM, '', 'ecb', '');
				$iv 	= mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
				# process the key
				$key 	= substr($key, 0, mcrypt_enc_get_key_size($td));
				# init mcrypt
				mcrypt_generic_init($td, $key, $iv);
	
				# decrypt the data and return
				$decrypt = mdecrypt_generic($td, $str);
	
				# shutdown mcrypt
				mcrypt_generic_deinit($td);
				mcrypt_module_close($td);
			}
			else
			{
				# if mcrypt doesn't exist use regular decryption method
				# init the decrypt vars
				$decrypt 	= '';

				# loop through the text and decode the string
				for($i=1; $i<=strlen($str); $i++)
				{
					$char 		= substr($str, $i-1, 1);
					$keychar 	= substr($key, ($i % strlen($key))-1, 1);
					$char 		= chr(ord($char)-ord($keychar));
					$decrypt   .= $char;
				}
			}
			# return the key
			return unserialize($decrypt);
		}
		
		/**
		* _wrap_license
		*
		* wraps up the license key in a nice little package
		*
		* @access private 
		* @param $src_array array The array that needs to be turned into a license str
		* @param $key_type string The type of key to be wrapped (KEY=license key, REQUESTKEY=license request key)
  		* @return string Returns encrypted and formatted license key
		**/
		function _wrap_license($src_array, $key_type='KEY')
		{
			# sort the variables
			$begin 	= $this->_pad($this->_get_begin($key_type));
			$end 	= $this->_pad($this->_get_end($key_type));
			
			# encrypt the data
			$str 	= $this->_encrypt($src_array, $key_type);
			
			# return the wrap
			return $begin.$this->_LINEBREAK.wordwrap($str, $this->_WRAPTO, $this->_LINEBREAK, 1).$this->_LINEBREAK.$end;
		}
		
		/**
		* _unwrap_license
		*
		* unwraps license key back into it's data array
		*
		* @access private 
		* @param $enc_str string The encrypted license key string that needs to be decrypted
		* @param $key_type string The type of key to be unwrapped (KEY=license key, REQUESTKEY=license request key)
  		* @return array Returns license data array
		**/
		function _unwrap_license($enc_str, $key_type='KEY')
		{
			# sort the variables
			$begin 	= $this->_pad($this->_get_begin($key_type));
			$end 	= $this->_pad($this->_get_end($key_type));
			
			# get string without seperators
			$str 	= trim(str_replace(array($begin, $end, "\r", "\n", "\t"), '', $enc_str));

			# decrypt and return the key
			return $this->_decrypt($str, $key_type);
		}
		
		/**
		* make_secure
		*
		* deletes all class values to prevent re-writing of a key;
		*
		* @access public 
		**/
		function make_secure($report=false)
		{
			if($report) define('_PADL_REPORT_ABUSE_', true);
			# walkthrough and delete the class vars
			foreach(array_keys(get_object_vars($this)) as $value)
			{
				unset($this->$value);
			}
			# define that class is secure
			define('_PADL_SECURE_', 1);
		}
		
		/**
		* _check_secure
		*
		* checks to see if the class has been made secure
		*
		* @access private 
		**/
		function _check_secure()
		{
			# check to see if padl has been made secure
			if(defined('_PADL_SECURE_')) 
			{	
				# if(defined('_PADL_REPORT_ABUSE_')) $this->_post_data($this->_HOST, $this->_PATH, array());
				# trigger the error because user has attempted to access secured functions
				# after the call has been made to 'make_secure'
				trigger_error("<br /><br /><span style='color: #F00;font-weight: bold;'>The PHP Application Distribution License System (PADL) has been made secure.<br />You have attempted to use functions that have been protected and this has terminated your script.<br /><br /></span>", E_USER_ERROR);
				exit;
			}
		}
		
	}

	/**
	* custom functions to aid in debugging
	*
	* @var mixed
	*/
	function trace()
	{
		$message = '';
		for ($i=0; $i<func_num_args(); $i++) 
		{
			if(is_array(func_get_arg($i)))
			{
				trace_r(func_get_arg($i));
			}
			else
			{
				$message .= func_get_arg($i);
			}
			if($i <= func_num_args()-2)
			{
				$message.=' : ';
			}
		}
		echo "<br><b>\r\r".$message."\r\r</b>";
	}
	function trace_r($array="array is empty")
	{
		echo "<pre><b>\r\r";
		print_r($array);
		echo "\r\r</b></pre>";
	}
	
?>
Return current item: PADL (PHP Application Distribution License System)