PHP Classes
Icontem

File: server/class.license.server.php


  Search   All class groups All class groups   Latest entries Latest entries   Top 10 charts Top 10 charts   Newsletter Newsletter   Blog Blog   Forums Forums   Help FAQ Help FAQ  
  Login   Register  
Recommend this page to a friend! ReTweet ReTweet Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Oliver Lillie  >  PADL (PHP Application Distribution License System)  >  server/class.license.server.php  
File: server/class.license.server.php
Role: Class source
Content type: text/plain
Description: Subclass Source
Class: PADL (PHP Application Distribution License System)
Generate PHP application license keys
 

Contents

Class file image Download
<?php

	/**
	* Project:		Distrubution License Class
	* File:			class.license.server.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 license_server extends padl {
	
		/**
		* init the database value.
		*/
		var $_DB;

		/**
		* the database table prefix.
		*
		* @var array
		*/
		var $DB_PREFIX			= '';
		
		/**
		* the default license approval type. 
		*			- ADMIN means the key generation needs admin approval
		*			- AUTO means the key generation is done on request
		*
		* @var string
		*/
		var $APPROVAL_TYPE		= 'ADMIN';
		
		/**
		* init the approval type vars.
		*/
		var $APPROVAL_DATA;
		var $APPROVAL_TIME;

		/**
		* Constructor
		*
		* @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 license_server($use_mcrypt=true, $use_time=true, $use_server=true, $allow_local=false, $approval_type=false)
		{
			# init the class
			$this->init($use_mcrypt, $use_time, $use_server, $allow_local);
			# set the registration approval type
			if(is_string($approval_type))
			{
				$this->set_approval_type($approval_type);
			}
		}
		
		/**
		* set_approval_type
		*
		* sets the approval type
		*
		* @access public 
		* @param $type string The type of license generation
		*		 ADMIN 	- generates a temp key and assigns the $data param into the key.
		*				  the key will be valid for the period set by the validty param.
		*							  NOTE: if validity is set to 0 then a key is not returned to the client
		*		AUTO	- generates the key when one is asked for. the data array is used, however
		*				  the validity period is treated as a cap for the time span sent from the client
		*				  install, thus if the validy is less than the asked for time period it will override
		* @param $data array An array of data to be bound into the generated key
		* @param $validity number If used with ADMIN it is the length of the temporary key generated. if set to 0
		*				  then no temp key is generated, however if used with AUTO it caps the requested licenses
		*				  time span. If no time span is requested by the client and this is not set to 0 then a span
		*				  will be placed into the key. This way you can issue licenses and not worry about the client
		*				  trying to hack the timespan of the license.
  		* @return resource id
		**/
		function set_approval_type($type='ADMIN', $data=array(), $validity=0)
		{
			$this->APPROVAL_TYPE = $type;
			$this->APPROVAL_DATA = $data;
			$this->APPROVAL_TIME = $validity;
		}

		/**
		* connect
		*
		* connects to the mysql db holding the license data
		*
		* @access public 
		* @param $table string Database table that contains the distributionLicense sql
		* @param $user string User for the mysql db
		* @param $pass string Pass for the mysql db
		* @param $host string Host for the mysql db
  		* @return resource id
		**/
		function connect($table, $user, $pass, $host='localhost')
		{
			# connect to your servers DB
			$this->_DB = @mysql_pconnect($host, $user, $pass);
			# select the table required
			@mysql_select_db($table, $this->_DB);
			return $this->_DB;
		}
		
		/**
		* disconnect
		*
		* disconnects the mysql db
		* been validated on the return server
		*
		* @access public 
  		* @return boolean 
		**/
		function disconnect()
		{
			# close the database
			return @mysql_close($this->_DB);
		}
		
		/**
		* _query
		*
		* builds, then excecutes then returns data for mysql queries 
		*
		* @access private 
		* @param $table string The table to build the query for
		* @param $action string The type of action to build the query for
		* @param $data array The data array containing arguments for the query building
  		* @return array 
		**/
		function _query($table, $action, $data=array())
		{
			$query =  $this->_build_query($table, $action, $data);
			return $this->_execute_query($query);
		}
		
		/**
		* _execute_query
		*
		* excecutes a mysql query and returns the results
		*
		* @access private 
		* @param $query string The query string to execute
  		* @return array 
		**/
		function _execute_query($query)
		{
			# determine the query type
			$query_type = strpos($query, 'INSERT')===false ? (strpos($query, 'SELECT')===false ? 'other' : 'return') : 'insert';
			# run the query
			$query_result = @mysql_query($query, $this->_DB);
			if(!$query_result) return array('RESULT'=>false, 'SQL'=>$query, 'ERROR'=>mysql_error());
			# switch through the query types in order to return the correct data
			switch($query_type)
			{
				case 'insert' :
					$result = mysql_insert_id($this->_DB);
					break;
				case 'return' :
					$result = array();
					if(empty($data['FETCHTYPE']))
					{
						while($row = mysql_fetch_assoc($query_result))
						{
							$result[] = $row;
						}
					}
					break;
				default :
					$result = true;
					break;
			}
			return array('RESULT'=>$result);
		}
		
		/**
		* _build_query
		*
		* gets the query for the table and qction
		*
		* @access private 
		* @param $table string The table to build the query for
		* @param $action string The type of action to build the query for
		* @param $data array The data array containing arguments for the query building
  		* @return string 
		**/
		function _build_query($table, $action, $data=array())
		{
			# get the table prefix and all
			$table_pre = '`'.$this->DB_PREFIX.$table.'`';
			# switch through the queries
			# and build them
			switch($action)
			{
				case 'insert' :
					switch($table)
					{
						case 'licenses' : 
							return 'INSERT INTO '.$table_pre.' (`LICENSE_ID`,`USER_ID`,`FLAGGED`,`STATUS`,`START_DATE`,`DATE_SPAN`,`EXPIRY_DATE`,`NOTES`,`COST`,`PAID`,`REQUEST_KEY`,`TEMP_KEY`,`LICENSE_KEY`,`PAYMENT_NEXT_DUE`,`DATA`,`MAC`,`PATH`,`IP`) VALUES ('.$this->_get_value($data['LICENSE_ID']).','.$this->_get_value($data['USER_ID']).','.$this->_get_value($data['FLAGGED']).','.$this->_get_value($data['STATUS']).','.$this->_get_value($data['START_DATE']).','.$this->_get_value($data['DATE_SPAN']).','.$this->_get_value($data['EXPIRY_DATE']).','.$this->_get_value($data['NOTES']).','.$this->_get_value($data['COST']).','.$this->_get_value($data['PAID']).','.$this->_get_value($data['REQUEST_KEY']).','.$this->_get_value($data['TEMP_KEY']).','.$this->_get_value($data['LICENSE_KEY']).','.$this->_get_value($data['PAYMENT_NEXT_DUE']).','.$this->_get_value($data['DATA']).','.$this->_get_value($data['MAC']).','.$this->_get_value($data['PATH']).','.$this->_get_value($data['IP']).');';
						case 'remote_log' :
							return 'INSERT INTO '.$table_pre.' (`ID`,`TIMESTAMP`,`LICENSE_ID`,`MESSAGE`,`SERVER`,`IP`) VALUES ('.$this->_get_value($data['ID']).','.$this->_get_value($data['TIMESTAMP']).','.$this->_get_value($data['LICENSE_ID']).','.$this->_get_value($data['MESSAGE']).','.$this->_get_value($data['SERVER']).','.$this->_get_value($data['IP']).');';
					}
				case 'return' :
					return 'SELECT '.$this->_get_value($data['RETURN'], '*', false).' FROM '.$table_pre.' '.$this->_build_matches($data['PAIRS']);
				case 'update' :
					return 'UPDATE '.$table_pre.' '.$this->_build_matches($data['SET'], 'SET', ', ').' '.$this->_build_matches($data['PAIRS']);
				case 'delete' :
					return 'DELETE FROM '.$table_pre.' '.$this->_build_matches($data['PAIRS']);
			}
		}
		
		/**
		* _get_value
		*
		* returns a null string if no value is found
		*
		* @access private 
		* @param $value string A value to be checked
		* @param $fill string The return value if the value is empty
  		* @return string 
		**/
		function _get_value($value, $fill='NULL', $add_quotes=true)
		{
			return empty($value) ? $fill : (is_string($value) && $add_quotes ? '"'.$value.'"' : $value);
		}
		
		/**
		* get_null
		*
		* returns formatted sql, ie `FIELD`="VALUE"
		*
		* @access private 
		* @param $pairs array An arrary containing the field/value pairs
		* @param $pre string The matches preceding command
		* @param $sep string The matches seperator
  		* @return string 
		**/
		function _build_matches($pairs, $pre='WHERE', $sep=' && ')
		{
			$num = count($pairs);
			# if there are no pairs return and empty string
			if($num == 0) return '';
			# init the string
			$str = $pre." ";
			# loop through the pairs and build the sql
			for($i=0; $i<$num; $i++)
			{
				$pair 		= $pairs[$i];
				$value 		= $pair['VALUE'];
				$comparison = empty($pair['COMP']) ? '=' : $pair['COMP'];
				$str 	.= '`'.$pair['FIELD'].'`'.$comparison.(is_string($value) ? '"'.$value.'"' : $value);
				if($i < $num-1)
				{
					$str.= $sep;
				}
			}
			return $str;
		}
		
		/**
		* _generate_return_data
		*
		* generates an encrypted string used to return data once the license has
		* been validated on the return server
		*
		* @access private 
		* @param $array array Array that contains the return info from the dial home server
  		* @return string encrypted data string containing server validation info
		**/
		function _generate_return_data($array)
		{
			return $this->BEGIN2.$this->_encrypt($array, 'HOMEKEY').$this->END2;
		}
		
		/**
		* receiveInstall
		*
		* receives an install and license key request. It validates the install
		* request, process it and checks for duplicates against the allow install
		* number, then returns with the result
		*
		* @access public 
		* @param $data array Data array (ie $_POST['POSTDATA']) recieved from
		*					 the client dialing home
		* @param $table string Database table that contains the distributionLicense sql
		* @param $user string User for the mysql db
		* @param $pass string Pass for the mysql db
		* @param $host string Host for the mysql db
  		* @return string Returns the encrypted result from the register_install function in the app
  		*			EMPTY_DATA					- no data has been given to the _recieve_call function
  		*			OVER_INSTALLED				- if the number of installs registered is too many then it is returned
  		*			CORRUPT						- the request does not contain an id and is therefore a corrupt / hacked request
  		*			PENDING						- the data is ok, however the approval type for license generation is set to ADMIN
  		*										  thus any key generation needs to be approved by an administrator
  		*			OK							- the license correspods to the info held on the home server and all is ok
		**/
		function receive_install($data, $table, $user, $pass, $host='localhost')
		{
			$orig_data = $data;
			# init the return array
			$return = array();
			
			# if there is not data die with an error
			if(empty($data)) return $this->_generate_return_data(array('RESULT'=>'EMPTY_DATA'));
			
			# decrypt the data
			$data = $this->_decrypt($data, 'HOMEKEY');
			
			# check for an id
			if($data['ID'] != md5($this->ID2)) return $this->_generate_return_data(array('RESULT'=>'CORRUPT'));
			
			# init the results array
			$results = array();
			# init the license array
			$license = array();

			# insert the id
			$license['ID'] = md5($this->ID1);
			
			# if server checks are required
			if($this->USE_SERVER)
			{
				if(!$this->_compare_domain_ip($data['SERVER']['DOMAIN'], $data['SERVER']['IP'])) $return['RESULT'] = 'DOMAIN_IP_FAIL';
				# update mac address
				$license['SERVER']['DOMAIN']= $data['SERVER']['DOMAIN'];
				# update mac address
				$license['SERVER']['MAC'] 	= $data['SERVER']['MAC'];
				# update the server details
				$license['SERVER']['PATH'] 	= $data['SERVER']['PATH'];
				# update the ip details
				$license['SERVER']['IP'] 	= $data['SERVER']['IP'];
			}
			
			# if time checks are required
			if($this->USE_TIME)
			{
				$license['DATE']['START'] 	= $data['DATE']['START'];
				$license['DATE']['SPAN'] 	= $data['DATE']['SPAN'];
				$license['DATE']['END'] 	= $data['DATE']['END'];
			}
			
			# connect to the db
			$this->connect($table, $user, $pass, $host);

			if(!empty($data['KEY_CODE']))
			{
				# will build in pre approved key codes, thus allowing someone to purchase
				# a license to get a key code. This key code is linked to an individual
				# licensee. If the license key has not been used already and is valid 
				# the license will be generated straight away, regardless of the generation
				# approval variables. It will generate will the the purchase settings from 
				# the database
			}

			# merge the exiting data set in the request with the approval data
			$license['DATA'] = array_merge($data['DATA'], $this->APPROVAL_DATA);
					
			if(!isset($return['RESULT'])) 
			{
				# start building the insertion query
				$query = 'INSERT INTO `'.$this->DB_PREFIX.'licenses` (`LICENSE_ID`,`USER_ID`,`FLAGGED`,`STATUS`,`START_DATE`,`DATE_SPAN`,`EXPIRY_DATE`,`NOTES`,`COST`,`PAID`,`REQUEST_KEY`,`TEMP_KEY`,`LICENSE_KEY`,`PAYMENT_NEXT_DUE`,`INSTALL`,`PACKAGES`,`MAC`,`PATH`,`IP`) VALUES (-VALUES-);';
				
				# sort the approval type
				if($this->APPROVAL_TYPE == 'AUTO')
				{
					# if the approval time is greater than 0 then override the end time
					if($this->APPROVAL_TIME > 0)
					{
						# set the time span of the temp key
						$start 						= time();
						$license['DATE']['START'] 	= $start;
						$license['DATE']['SPAN'] 	= $this->APPROVAL_TIME;
						$license['DATE']['END'] 	= $start+$this->APPROVAL_TIME;
					}
					$create_license = true;
					$return['RESULT'] 	= 'OK';
					$values = 'NULL,NULL,NULL,1,'.$license['DATE']['START'].','.$license['DATE']['SPAN'].','.$license['DATE']['END'].',NULL,NULL,1,"'.$orig_data.'",NULL,NULL,NULL,NULL,NULL,"'.$data['SERVER']['MAC'].'","'.urlencode(serialize($data['SERVER']['PATH'])).'","'.urlencode(serialize($data['SERVER']['IP'])).'"';
				}
				else if($this->APPROVAL_TYPE == 'ADMIN')
				{
					$key = '';
					# if the approval time is greater than 0 generate a temp key
					if($this->APPROVAL_TIME > 0)
					{
						# set the time span of the temp key
						$start 						= time();
						$license['DATE']['START'] 	= $start;
						$license['DATE']['SPAN'] 	= $this->APPROVAL_TIME;
						$license['DATE']['END'] 	= $start+$this->APPROVAL_TIME;
						$license['TEMP'] = 1;
						$create_license = true;
					}
					$values = 'NULL,NULL,NULL,1,'.$license['DATE']['START'].','.$license['DATE']['SPAN'].','.$license['DATE']['END'].',NULL,NULL,NULL,"'.$orig_data.'",NULL,NULL,NULL,NULL,NULL,"'.$data['SERVER']['MAC'].'","'.urlencode(serialize($data['SERVER']['PATH'])).'","'.urlencode(serialize($data['SERVER']['IP'])).'"';
					$return['RESULT'] 	= 'PENDING';
				}
				$query = str_replace('-VALUES-', $values, $query);
				if(!mysql_query($query, $this->_DB))
				{
					$return['ERROR'] = mysql_error();
					$return['RESULT'] = 'SERVER_DB_FAILED';
					$create_license = false;
				}
				
				if($create_license)
				{
					$license['DBID'] = mysql_insert_id($this->_DB);
					# create the key
					$key = $this->_create_license($license);
					$return['KEY'] 	= $key;
					$row = ($this->APPROVAL_TYPE == 'ADMIN') ? 'TEMP_KEY' : 'LICENSE_KEY';
					if(!mysql_query('UPDATE `'.$this->DB_PREFIX.'licenses` SET `'.$row.'`="'.$key.'" WHERE `LICENSE_ID`="'.$license['DBID'].'"'))
					{
						$return['ERROR'] = mysql_error();
						$return['RESULT'] = 'SERVER_DB_FAILED';
						unset($return['KEY']);
					}
				}

			}
			
			# disconnect from the db
			$this->disconnect();
			
			# generate the return data
			return $this->_generate_return_data($return);
		}
		
		/**
		* generate
		*
		* generates the client license key
		*
		* @access private 
		* @param $data array The data array containing the binding info
  		* @return string key string
		**/
		function _create_license($data)
		{
			# set the server os
			$data['DATA']['_PHP_OS'] 	 	= PHP_OS;  
			# set the server os
			$data['DATA']['_PHP_VERSION'] 	= PHP_VERSION;  
			# encrypt the key and return
			return $this->_wrap_license($data);
		}

		/**
		* recieve_call
		*
		* the function to be called by the script that recieves the call on your
		* server from the client server
		*
		* @access public 
		* @param $data array Data array (ie $_POST['POSTDATA']) recieved from
		*					 the client dialing home
		* @param $table string Database table that contains the distributionLicense sql
		* @param $user string User for the mysql db
		* @param $pass string Pass for the mysql db
		* @param $host string Host for the mysql db
  		* @return string Returns the encrypted server validation result from the dial home call
  		*			EMPTY_DATA					- no data has been given to the _recieve_call function
  		*			EMPTY_ID					- no id has been found in the data sent so dial home check cannot be made
  		*			SERVER_LICENSE_404			- the license does not exist on the dial home server
  		*			SERVER_LICENSE_MISMATCH		- the license key sent to the home server and the license key residing in the 
  		*										  home server db do not match
  		*			SERVER_LICENSE_INACTIVE		- license is inactive (ie expired)
  		*			SERVER_LICENSE_WARNING		- a warning has been given to the license holder
  		*			SERVER_LICENSE_SUSPENDED	- the license has been suspended
  		*			SERVER_LICENSE_REVOKED		- license has been revoked
  		*			SERVER_PAYMENT_NOT_MADE		- license has not been paid for
  		*			SERVER_PAYMENT_DUE			- next payment is due
  		*			SERVER_DATE_MISMATCH		- license start date does not match the one on the dial home server
  		*			SERVER_MAC_MISMATCH			- the mac address registered with the license does not match the one on the home server
  		*			SERVER_SERVER_MISMATCH		- the server vars supplied in the license mismatch the stored vars on the home server
  		*			OK							- the license correspods to the info held on the home server and all is ok
		**/
		function recieve_call($data, $table, $user, $pass, $host='localhost')
		{
			# if there is not data die with an error
			if(empty($data))
			{
				return $this->_generate_return_data(array('RESULT'=>'EMPTY_DATA'));
			}
			# init the results array
			$results = array();
			# decrypt the data
			$data = $this->_decrypt($data, 'HOMEKEY');

			# if there is no license id to check then return with error
			if(!isset($data['LICENSE_DATA']['DBID']))
			{
				return $this->_generate_return_data(array('RESULT'=>'EMPTY_ID'));
			}
			
			$istemp = (isset($data['LICENSE_DATA']['TEMP']));

			# connect to the db
			$this->connect($table, $user, $pass, $host);

			# insert log remote log data
			mysql_query('INSERT INTO `'.$this->DB_PREFIX.'remote_log` (`ID`,`TIMESTAMP`,`LICENSE_ID`,`MESSAGE`,`SERVER`,`IP`) VALUES (NULL,"'.time().'","'.$data['LICENSE_DATA']['DBID'].'","'.'test'.'","'.urlencode(serialize($data['LICENSE_DATA']['SERVER']['PATH'])).'","'.$_SERVER['REMOTE_ADDR'].'")', $this->_DB);

			# check up on license in the license table
			$lookup_result = mysql_query('SELECT * FROM `'.$this->DB_PREFIX.'licenses` WHERE `LICENSE_ID`="'.$data['LICENSE_DATA']['DBID'].'"', $this->_DB);
 			# get the license data from the server
			$license = mysql_fetch_array($lookup_result, MYSQL_ASSOC);
			
			# disconnect from the db
			$this->disconnect();

			# if the result is not returned or the license does not exist			
			if(!$lookup_result || !$license)
			{
				# die and send back the result to the server calling home
				return $this->_generate_return_data(array('RESULT'=>'SERVER_LICENSE_404'));
			}

			# compare the license sent against the license stored
			# if any changes have been made to the clients license without updating the one
			# on the server then this will throw an error, main cause would be a hack or
			# developer error
			$stored_key = ($istemp) ? $license['TEMP_KEY'] : $license['LICENSE_KEY'];
			if(md5($stored_key) != $data['LICENSE_DATA']['KEY'])
			{
				return $this->_generate_return_data(array('RESULT'=>'SERVER_LICENSE_MISMATCH'));
			}
			
			# check if license is active
			switch($license['STATUS'])
			{
				case 0 :
					return $this->_generate_return_data(array('RESULT'=>'SERVER_LICENSE_INACTIVE'));
				case -1 :
					return $this->_generate_return_data(array('RESULT'=>'SERVER_LICENSE_WARNING'));
				case -2 :
					return $this->_generate_return_data(array('RESULT'=>'SERVER_LICENSE_SUSPENDED'));
				case -3 :
					return $this->_generate_return_data(array('RESULT'=>'SERVER_LICENSE_REVOKED'));
				default :
					break;
			}

			# check if user has paid
			if(!$license['PAID'] && !$istemp)
			{
				return $this->_generate_return_data(array('RESULT'=>'SERVER_PAYMENT_NOT_MADE'));
			}

			# check if the next pay date is passed
			if($license['PAYMENT_NEXT_DUE']>0 && $license['PAYMENT_NEXT_DUE']  < time())
			{
				return $this->_generate_return_data(array('RESULT'=>'SERVER_PAYMENT_DUE'));
			}

			# check the start date and see if it is valid
			if($this->USE_TIME && ($license['START_DATE'] != $data['LICENSE_DATA']['DATE']['START'] || $license['EXPIRY_DATE'] != $data['LICENSE_DATA']['DATE']['END']))
			{
				return $this->_generate_return_data(array('RESULT'=>'SERVER_DATE_MISMATCH'));
			}

			# if server checks are required
			if($this->USE_SERVER)
			{
				# check mac address
				if($license['MAC'] != $data['LICENSE_DATA']['SERVER']['MAC'])
				{
					return $this->_generate_return_data(array('RESULT'=>'SERVER_MAC_MISMATCH'));
				}

				# check the server vars
				$server_difs = count(array_diff(unserialize(urldecode($license['PATH'])), $data['LICENSE_DATA']['SERVER']['PATH']));
				if($server_difs > 0)
				{
					return $this->_generate_return_data(array('RESULT'=>'SERVER_SERVER_MISMATCH'));
				}
			}
			
			return $this->_generate_return_data(array('RESULT'=>'OK'));
		}
		
	}

?>

 
  Advertise on this site Advertise on this site   Site map Site map   Statistics Statistics   Site tips Site tips   Privacy policy Privacy policy   Contact Contact  

For more information send a message to :
info at phpclasses dot org.
Copyright (c) Icontem 1999-2009 PHP Classes - PHP Class Scripts
  PHP Book Reviews - Reviews of books and other products