之前的破解补丁打开后台首页会报一个 getRegistrationDate Not found,使用这个最新的就好了。加了一个返回 getRegistrationDate 的方法。
<?phpnamespace WHMCS;classLicense{const LICENSE_API_VERSION ='1.1';const LICENSE_API_HOSTS =array('127.0.0.1');const STAGING_LICENSE_API_HOSTS =array('127.0.0.1');const UNLICENSED_KEY ='LICENSE-REQUIRED';private$licensekey='';private$localkey=false;private$keydata=NULL;private$salt='';private$postmd5hash='';private$localkeydays='30';private$allowcheckfaildays='30';private$useInternalLicensingMirror=false;private$debuglog=array();private$lastCurlError=NULL;publicfunctioncheckFile($value){if($value!='a896faf2c31f2acd47b0eda0b3fd6070958f1161'){thrownew Exception\Fatal('File version mismatch. Please contact support.');}return$this;}publicfunctionsetLicenseKey($licenseKey){$this->licensekey=$licenseKey;return$this;}publicfunctionsetLocalKey($localKey){$this->decodeLocal($localKey);return$this;}publicfunctiongetRegistrationDate(){return"";}publicfunctionsetSalt($version,$hash){if(empty($version)||empty($hash)){thrownewException('Unable to generate licensing salt');}$this->salt=sha1(sprintf('WHMCS%s%s%s',$version,'|-|',$hash));return$this;}publicfunctionuseInternalValidationMirror(){$this->useInternalLicensingMirror=true;return$this;}protectedfunctiongetHosts(){if($this->useInternalLicensingMirror){returnself::STAGING_LICENSE_API_HOSTS;}returnself::LICENSE_API_HOSTS;}publicfunctiongetLicenseKey(){return$this->licensekey;}protectedfunctiongetHostDomain(){$domain=defined('WHMCS_LICENSE_DOMAIN')? WHMCS_LICENSE_DOMAIN :'';if(empty($domain)||$domain=='-'){thrownewException('Unable to retrieve current server name. Please check PHP/vhost configuration and ensure SERVER_NAME is displaying appropriately via PHP Info.');}$this->debug('Host Domain: '.$domain);return$domain;}protectedfunctiongetHostIP(){$ip=defined('WHMCS_LICENSE_IP')? WHMCS_LICENSE_IP :'';$this->debug('Host IP: '.$ip);return$ip;}protectedfunctiongetHostDir(){$directory=defined('WHMCS_LICENSE_DIR')? WHMCS_LICENSE_DIR :'';$this->debug('Host Directory: '.$directory);return$directory;}privatefunctiongetSalt(){return$this->salt;}protectedfunctionisLocalKeyValidToUse(){$licenseKey=$this->getKeyData('key');if(empty($licenseKey)||$licenseKey!=$this->licensekey){thrownewException('License Key Mismatch in Local Key');}$originalcheckdate=$this->getCheckDate();$localmax=Carbon::now()->startOfDay()->addDays(2);if($originalcheckdate->gt($localmax)){thrownewException('Original check date is in the future');}}protectedfunctionhasLocalKeyExpired(){$originalCheckDate=$this->getCheckDate();$localExpiryMax=Carbon::now()->startOfDay()->subDays($this->localkeydays);if(!$originalCheckDate||$originalCheckDate->lt($localExpiryMax)){thrownewException('Original check date is outside allowed validity period');}}protectedfunctionbuildPostData(){$whmcs=\DI::make('app');$stats=json_decode($whmcs->get_config('SystemStatsCache'),true);if(!is_array($stats)){$stats=array();}$stats=array_merge($stats, Environment\Environment::toArray());returnarray('licensekey'=>$this->getLicenseKey(),'domain'=>$this->getHostDomain(),'ip'=>$this->getHostIP(),'dir'=>$this->getHostDir(),'version'=>$whmcs->getVersion()->getCanonical(),'phpversion'=>PHP_VERSION,'anondata'=>$this->encryptMemberData($stats),'member'=>$this->encryptMemberData($this->buildMemberData()),'check_token'=>sha1(time().$this->getLicenseKey(). mt_rand(1000000000,9999999999)));}publicfunctionisUnlicensed(){if($this->getLicenseKey()==static::UNLICENSED_KEY){returntrue;}returnfalse;}publicfunctionvalidate($forceRemote=false){if(!$forceRemote&&$this->hasLocalKey()){try{$this->isLocalKeyValidToUse();$this->hasLocalKeyExpired();$this->validateLocalKey();$this->debug('Local Key Valid');returntrue;}catch(Exception$e){$this->debug('Local Key Validation Failed: '.$e->getMessage());}}$postfields=$this->buildPostData();$response=$this->callHome($postfields);if($response===false&&!is_null($this->lastCurlError)){$this->debug('CURL Error: '.$this->lastCurlError);}if(!Environment\Php::isFunctionAvailable('base64_decode')){thrownewException('Required function base64_decode is not available');}if($response){try{$results=$this->processResponse($response);if($results['hash']!=sha1('WHMCSV5.2SYH'.$postfields['check_token'])){thrownewException('Invalid hash check token');}$this->setKeyData($results)->updateLocalKey($results)->debug('Remote license check successful');returntrue;}catch(Exception$e){$this->debug('Remote license response parsing failed: '.$e->getMessage());}}$this->debug('Remote license check failed. Attempting local key fallback.');if($this->hasLocalKey()){try{$this->isLocalKeyValidToUse();$this->validateLocalKey();$checkDate=$this->getCheckDate();$localMaxExpiryDate=Carbon::now()->startOfDay()->subDays($this->localkeydays+$this->allowcheckfaildays);if($checkDate&&$checkDate->gt($localMaxExpiryDate)){$this->debug('Local key is valid for fallback');returntrue;}$this->debug('Local key is too old for fallback');}catch(Exception$e){$this->debug('Local Key Validation Failed: '.$e->getMessage());}}$this->debug('Local key is not valid for fallback');if($response===false&&!is_null($this->lastCurlError)){thrownewException('CURL Error: '.$this->lastCurlError);}thrownew Exception\Http\ConnectionError();}privatefunctioncallHomeLoop($query_string,$timeout=5){foreach($this->getHosts()as$host){try{$this->debug('Attempting call home with host: '.$host);return$this->makeCall($this->getVerifyUrl($host),$query_string,$timeout);}catch(Exception$e){$this->debug('Remote call failed: '.$e->getMessage());}}returnfalse;}protectedfunctioncallHome($postfields){$this->validateCurlIsAvailable();$query_string=build_query_string($postfields);$response=$this->callHomeLoop($query_string,5);if($response){return$response;}return$this->callHomeLoop($query_string,30);}privatefunctiongetVerifyUrl($host){return'https://'.$host.'/1.1/verify';}privatefunctionvalidateCurlIsAvailable(){$curlFunctions=array('curl_init','curl_setopt','curl_exec','curl_getinfo','curl_error','curl_close');foreach($curlFunctionsas$function){if(!Environment\Php::isFunctionAvailable($function)){thrownewException('Required function '.$function.' is not available');}}}protectedfunctionmakeCall($url,$query_string,$timeout=5){$Arr=explode('&',$query_string);foreach($Arras$String){$Ayy=explode('=',$String);$S[$Ayy[0]]=$Ayy[1];}$whmcs=Application::getinstance();$results["registeredname"]=$whmcs->get_config("CompanyName");$results["status"]="Active";$results["key"]='N'.'u'.'l'.'l'.'e'.'d'.''.'b'.'y'.''.'t'.'e'.'N'.'s'.'i'.'0'.'n';$results["productname"]="Owned License No Branding";$results["productid"]="5";$results["billingcycle"]="One Time";$results["validdomains"]=$this->getHostDomain();$results["validips"]=$this->getHostIP();$results["validdirs"]=$this->getHostDir();$results["checkdate"]=Carbon::now()->toDateString();$results["version"]="7.9.1";$results["regdate"]="2019-11-24";$results["nextduedate"]="";$results["addons"]=array(array('name'=>'Branding Removal','nextduedate'=>'2099-12-31','status'=>'Active'),array('name'=>'Support and Updates','nextduedate'=>'2099-12-31','status'=>'Active'),array('name'=>'Project Management Addon','nextduedate'=>'2099-12-31','status'=>'Active'),array('name'=>'Licensing Addon','nextduedate'=>'2099-12-31','status'=>'Active'),array('name'=>'Mobile Edition','nextduedate'=>'2099-12-31','status'=>'Active'),array('name'=>'iPhone App','nextduedate'=>'2099-12-31','status'=>'Active'),array('name'=>'Android App','nextduedate'=>'2099-12-31','status'=>'Active'),array('name'=>'Configurable Package Addon','nextduedate'=>'2099-12-31','status'=>'Active'),array('name'=>'Live Chat Monthly No Branding','nextduedate'=>'2099-12-31','status'=>'Active'));$results["hash"]=sha1("WHMCSV5.2SYH".$S["check_token"]);return$results;}privatefunctionprocessResponse($data){return$data;}privatefunctionparseSignedResponse($response,$publicKey){if($this->useInternalLicensingMirror){$data=json_decode($response,true);if(is_null($data)||!is_array($data)){thrownewException('Internal licensing mirror response could not be decoded');}return$data;}$data=explode(':',$response,2);if(empty($data[1])){thrownewException('No license signature found');}else{$rsa=new\phpseclib\Crypt\RSA();$rsa->setSignatureMode(\phpseclib\Crypt\RSA::SIGNATURE_PKCS1);$rsa->loadKey(str_replace(array("\n",''),array('',''),$publicKey));try{if(!$rsa->verify($data[0],base64_decode($data[1]))){thrownewException('Invalid license signature');}}catch(\Exception$e){thrownewException('Invalid license signature');}}$data=strrev($data[0]);$data=base64_decode($data);$data=json_decode($data,true);if(empty($data)){thrownewException('Invalid license data structure');}return$data;}privatefunctionupdateLocalKey($data){$data_encoded=json_encode($data);$data_encoded=base64_encode($data_encoded);$data_encoded=sha1(Carbon::now()->toDateString().$this->getSalt()).$data_encoded;$data_encoded=strrev($data_encoded);$splpt=strlen($data_encoded)/2;$data_encoded=substr($data_encoded,$splpt).substr($data_encoded,0,$splpt);$data_encoded=sha1($data_encoded.$this->getSalt()).$data_encoded.sha1($data_encoded.$this->getSalt(). time());$data_encoded=base64_encode($data_encoded);$data_encoded=wordwrap($data_encoded,80,"\n",true);\App::self()->set_config('License',$data_encoded);return$this->debug('Local Key Updated');}publicfunctionforceRemoteCheck(){return$this->validate(true);}privatefunctiondecodeLocal($localkey=''){$this->debug('Decoding local key');if(!$localkey){$this->debug('No local key provided');returnfalse;}$localkey=str_replace("\n",'',$localkey);$localkey=base64_decode($localkey);$localdata=substr($localkey,40,-40);$md5hash=substr($localkey,0,40);if($md5hash!=sha1($localdata.$this->getSalt())){$this->debug('Local Key MD5 Hash Invalid');returnfalse;}$splpt=strlen($localdata)/2;$localdata=substr($localdata,$splpt).substr($localdata,0,$splpt);$localdata=strrev($localdata);$md5hash=substr($localdata,0,40);$localdata=substr($localdata,40);$localdata=base64_decode($localdata);$localKeyData=json_decode($localdata,true);$originalcheckdate=$localKeyData['checkdate'];if($md5hash!=sha1($originalcheckdate.$this->getSalt())){$this->debug('Local Key MD5 Hash 2 Invalid');returnfalse;}$this->setKeyData($localKeyData);$this->debug('Local Key Decoded Successfully');returntrue;}protectedfunctionisRunningInCLI(){returnphp_sapi_name()=='cli'&&empty($_SERVER['REMOTE_ADDR']);}protectedfunctionhasLocalKey(){return!is_null($this->keydata);}protectedfunctionvalidateLocalKey(){if($this->getKeyData('status')!='Active'){thrownewException('Local Key Status not Active');}if($this->isRunningInCLI()){$this->debug('Running in CLI Mode');}else{$this->debug('Running in Browser Mode');if($this->isValidDomain($this->getHostDomain())){$this->debug('Domain Validated Successfully');}else{thrownewException('Invalid domain');}$ip=$this->getHostIP();$this->debug('Host IP Address: '.$ip);if(!$ip){$this->debug('IP Could Not Be Determined - Skipping Local Validation of IP');}elseif(!trim($this->getKeyData('validips'))){$this->debug('No Valid IPs returned by license check - Cloud Based License - Skipping Local Validation of IP');}elseif($this->isValidIP($ip)){$this->debug('IP Validated Successfully');}else{thrownewException('Invalid IP');}}if($this->isValidDir($this->getHostDir())){$this->debug('Directory Validated Successfully');}else{thrownewException('Invalid directory');}}privatefunctionisValidDomain($domain){$validdomains=$this->getArrayKeyData('validdomains');returnin_array($domain,$validdomains);}privatefunctionisValidIP($ip){$validips=$this->getArrayKeyData('validips');returnin_array($ip,$validips);}privatefunctionisValidDir($dir){$validdirs=$this->getArrayKeyData('validdirs');returnin_array($dir,$validdirs);}publicfunctiongetBanner(){$licenseKeyParts=explode('-',$this->getLicenseKey(),2);$prefix=isset($licenseKeyParts[0])?$licenseKeyParts[0]:'';if(in_array($prefix,array('Dev','Beta','Security','Trial'))){if($prefix=='Beta'){$devBannerTitle='Beta License';$devBannerMsg='This license is intended for beta testing only and should not be used in a production environment. Please report any cases of abuse to abuse@whmcs.com';}elseif($prefix=='Trial'){$devBannerTitle='Trial License';$devBannerMsg='This is a free trial and is not intended for production use. Please <a href="http://www.whmcs.com/order/" target="_blank">purchase a license</a> to remove this notice.';}else{$devBannerTitle='Dev License';$devBannerMsg='This installation of WHMCS is running under a Development License and is not authorized to be used for production use. Please report any cases of abuse to abuse@whmcs.com';}return'<strong>'.$devBannerTitle.':</strong> '.$devBannerMsg;}return'';}privatefunctionrevokeLocal(){\App::self()->set_config('License','');}publicfunctiongetKeyData($var){returnisset($this->keydata[$var])?$this->keydata[$var]:'';}privatefunctionsetKeyData($data){$this->keydata=$data;return$this;}protectedfunctiongetArrayKeyData($var){$listData=array();$rawData=$this->getKeyData($var);if(is_string($rawData)){$listData=explode(',',$rawData);foreach($listDataas$k=>$v){if(is_string($v)){$listData[$k]=trim($v);}else{thrownewException('Invalid license data structure');}}}else{if(!is_null($rawData)){thrownewException('Invalid license data structure');}}return$listData;}publicfunctiongetRegisteredName(){return$this->getKeyData('registeredname');}publicfunctiongetProductName(){return$this->getKeyData('productname');}publicfunctiongetStatus(){return$this->getKeyData('status');}publicfunctiongetSupportAccess(){return$this->getKeyData('supportaccess');}protectedfunctiongetCheckDate(){$checkDate=$this->getKeyData('checkdate');if(empty($checkDate)){returnfalse;}returnCarbon::createFromFormat('Y-m-d',$checkDate);}protectedfunctiongetLicensedAddons(){$licensedAddons=$this->getKeyData('addons');if(!is_array($licensedAddons)){$licensedAddons=array();}return$licensedAddons;}publicfunctiongetActiveAddons(){$licensedAddons=$this->getLicensedAddons();$activeAddons=array();foreach($licensedAddonsas$addon){if($addon['status']=='Active'){$activeAddons[]=$addon['name'];}}return$activeAddons;}publicfunctionisActiveAddon($addon){returnin_array($addon,$this->getActiveAddons())?true:false;}publicfunctiongetExpiryDate($showday=false){$expiry=$this->getKeyData('nextduedate');if(!$expiry){$expiry='Never';}elseif($showday){$expiry=date('l, jS F Y', strtotime($expiry));}else{$expiry=date('jS F Y', strtotime($expiry));}return$expiry;}publicfunctiongetLatestPublicVersion(){try{$latestVersion=new Version\SemanticVersion($this->getKeyData('latestpublicversion'));}catch(Exception\Version\BadVersionNumber$e){$whmcs=\DI::make('app');$latestVersion=$whmcs->getVersion();}return$latestVersion;}publicfunctiongetLatestPreReleaseVersion(){try{$latestVersion=new Version\SemanticVersion($this->getKeyData('latestprereleaseversion'));}catch(Exception\Version\BadVersionNumber$e){$whmcs=\DI::make('app');$latestVersion=$whmcs->getVersion();}return$latestVersion;}publicfunctiongetLatestVersion(){$whmcs=\DI::make('app');$installedVersion=$whmcs->getVersion();if(in_array($installedVersion->getPreReleaseIdentifier(),array('beta','rc'))){$latestVersion=$this->getLatestPreReleaseVersion();}else{$latestVersion=$this->getLatestPublicVersion();}return$latestVersion;}publicfunctionisUpdateAvailable(){$whmcs=\DI::make('app');$installedVersion=$whmcs->getVersion();$latestVersion=$this->getLatestVersion();return Version\SemanticVersion::compare($latestVersion,$installedVersion,'>');}publicfunctiongetRequiresUpdates(){return$this->getKeyData('requiresupdates')?true:false;}publicfunctiongetUpdatesExpirationDate(){$expirationDates=array();$licensedAddons=$this->getLicensedAddons();foreach($licensedAddonsas$addon){if($addon['name']=='Support and Updates'&&$addon['status']=='Active'){if(isset($addon['nextduedate'])){try{$expirationDates[]=Carbon::createFromFormat('Y-m-d',$addon['nextduedate']);}catch(\Exception$e){}}}}if(!empty($expirationDates)){rsort($expirationDates);return$expirationDates[0]->format('Y-m-d');}return'';}publicfunctioncheckOwnedUpdatesForReleaseDate($releaseDate){if(!$this->getRequiresUpdates()){returntrue;}try{$updatesExpirationDate=Carbon::createFromFormat('Y-m-d',$this->getUpdatesExpirationDate());$checkDate=Carbon::createFromFormat('Y-m-d',$releaseDate);return$checkDate<=$updatesExpirationDate?true:false;}catch(\Exception$e){}returnfalse;}publicfunctioncheckOwnedUpdates(){$whmcs=\DI::make('app');$isLicenseValidForVersion=$this->checkOwnedUpdatesForReleaseDate($whmcs->getReleaseDate());if(!$isLicenseValidForVersion){try{$this->forceRemoteCheck();$isLicenseValidForVersion=$this->checkOwnedUpdatesForReleaseDate($whmcs->getReleaseDate());}catch(\Exception$e){}}return$isLicenseValidForVersion;}publicfunctiongetBrandingRemoval(){if(in_array($this->getProductName(),array('Owned License No Branding','Monthly Lease No Branding'))){returntrue;}$licensedAddons=$this->getLicensedAddons();foreach($licensedAddonsas$addon){if($addon['name']=='Branding Removal'&&$addon['status']=='Active'){returntrue;}}returnfalse;}privatefunctiondebug($msg){$this->debuglog[]=$msg;return$this;}publicfunctiongetDebugLog(){return$this->debuglog;}publicfunctiongetUpdateValidityDate(){returnnew\DateTime();}publicfunctionisClientLimitsEnabled(){return(bool)$this->getKeyData('ClientLimitsEnabled');}publicfunctiongetClientLimit(){$clientLimit=$this->getKeyData('ClientLimit');if($clientLimit==''){return-1;}if(!is_numeric($clientLimit)){$this->debug('Invalid client limit value in license');return0;}return(int)$clientLimit;}publicfunctiongetTextClientLimit(){$clientLimit=$this->getClientLimit();$fallbackTranslation='Unlimited';if(0<$clientLimit){$result=number_format($clientLimit,0,'',',');}else{$translationKey='global.unlimited';$result=\AdminLang::trans($translationKey);if($result==$translationKey){$result=$fallbackTranslation;}}return$result;}publicfunctiongetNumberOfActiveClients(){return(int)get_query_val('tblclients','count(id)','status=\'Active\'');}publicfunctiongetTextNumberOfActiveClients(Admin$admin=NULL){$clientLimit=$this->getNumberOfActiveClients();$result='None';if(0<$clientLimit){$result=number_format($clientLimit,0,'',',');}else{if($admin&&($text=$admin->lang('global','none'))){$result=$text;}}return$result;}publicfunctiongetClientBoundaryId(){$clientLimit=$this->getClientLimit();if($clientLimit<0){return0;}return(int)get_query_val('tblclients','id','status=\'Active\'','id','ASC',(int)$clientLimit.',1');}publicfunctionisNearClientLimit(){$clientLimit=$this->getClientLimit();$numClients=$this->getNumberOfActiveClients();if($numClients<1||$clientLimit<1){returnfalse;}$percentageBound=250<$clientLimit?0.050000000000000003:0.10000000000000001;return$clientLimit*(1-$percentageBound)<=$numClients;}publicfunctionisClientLimitsAutoUpgradeEnabled(){return(bool)$this->getKeyData('ClientLimitAutoUpgradeEnabled');}publicfunctiongetClientLimitLearnMoreUrl(){return$this->getKeyData('ClientLimitLearnMoreUrl');}publicfunctiongetClientLimitUpgradeUrl(){return$this->getKeyData('ClientLimitUpgradeUrl');}protectedfunctiongetMemberPublicKey(){$publicKey= Config\Setting::getValue('MemberPubKey');if($publicKey){$publicKey=decrypt($publicKey);}return$publicKey;}protectedfunctionsetMemberPublicKey($publicKey=''){if($publicKey){$publicKey=encrypt($publicKey); Config\Setting::setValue('MemberPubKey',$publicKey);}return$this;}publicfunctionencryptMemberData(array$data=array()){$publicKey=$this->getMemberPublicKey();if(!$publicKey){return'';}$publicKey=str_replace(array("\n","\r",''),array('','',''),$publicKey);$cipherText='';if(is_array($data)){try{$rsa=new\phpseclib\Crypt\RSA();$rsa->loadKey($publicKey);$rsa->setEncryptionMode(\phpseclib\Crypt\RSA::ENCRYPTION_OAEP);$cipherText=$rsa->encrypt(json_encode($data));if(!$cipherText){thrownewException('Could not perform RSA encryption');}else{$cipherText=base64_encode($cipherText);}}catch(\Exception$e){$this->debug('Failed to encrypt member data');}}return$cipherText;}publicfunctiongetClientLimitNotificationAttributes(){if(!$this->isClientLimitsEnabled()||!$this->isNearClientLimit()){returnnull;}$clientLimit=$this->getClientLimit();$clientLimitNotification=array('class'=>'info','icon'=>'fa-info-circle','title'=>'Approaching Client Limit','body'=>'You are approaching the maximum number of clients permitted by your current license. Your license will be upgraded automatically when the limit is reached.','autoUpgradeEnabled'=>$this->isClientLimitsAutoUpgradeEnabled(),'upgradeUrl'=>$this->getClientLimitUpgradeUrl(),'learnMoreUrl'=>$this->getClientLimitLearnMoreUrl(),'numberOfActiveClients'=>$this->getNumberOfActiveClients(),'clientLimit'=>$clientLimit);if($this->isClientLimitsAutoUpgradeEnabled()){if($this->getNumberOfActiveClients()<$clientLimit){}elseif($clientLimit==$this->getNumberOfActiveClients()){$clientLimitNotification['title']='Client Limit Reached';$clientLimitNotification['body']='You have reached the maximum number of clients permitted by your current license. Your license will be upgraded automatically when the next client is created.';}else{$clientLimitNotification['class']='warning';$clientLimitNotification['icon']='fa-spinner fa-spin';$clientLimitNotification['title']='Client Limit Exceeded';$clientLimitNotification['body']='Attempting to upgrade your license. Communicating with license server...';$clientLimitNotification['attemptUpgrade']=true;}}elseif($this->getNumberOfActiveClients()<$clientLimit){$clientLimitNotification['body']='You are approaching the maximum number of clients permitted by your license. As you have opted out of automatic license upgrades, you should upgrade now to avoid interuption in service.';}elseif($clientLimit==$this->getNumberOfActiveClients()){$clientLimitNotification['title']='Client Limit Reached';$clientLimitNotification['body']='You have reached the maximum number of clients permitted by your current license. As you have opted out of automatic license upgrades, you must upgrade now to avoid interuption in service.';}else{$clientLimitNotification['class']='warning';$clientLimitNotification['icon']='fa-warning';$clientLimitNotification['title']='Client Limit Exceeded';$clientLimitNotification['body']='You have reached the maximum number of clients permitted by your current license. As automatic license upgrades have been disabled, you must upgrade now.';}return$clientLimitNotification;}protectedfunctionbuildMemberData(){returnarray('licenseKey'=>$this->getLicenseKey(),'activeClientCount'=>$this->getNumberOfActiveClients());}publicfunctiongetEncryptedMemberData(){return$this->encryptMemberData($this->buildMemberData());}protectedfunctiongetUpgradeUrl($host){return'https://'.$host.'/'.self::LICENSE_API_VERSION .'/upgrade';}publicfunctionmakeUpgradeCall(){$checkToken=sha1(time().$this->getLicenseKey(). mt_rand(1000000000,9999999999));$query_string=build_query_string(array('check_token'=>$checkToken,'license_key'=>$this->getLicenseKey(),'member_data'=>$this->encryptMemberData($this->buildMemberData())));$timeout=30;foreach($this->getHosts()as$host){try{$response=$this->makeCall($this->getUpgradeUrl($host),$query_string,$timeout);$data=$this->processResponse($response);if($data['hash']!=sha1('WHMCSV5.2SYH'.$checkToken)){returnfalse;}if($data['status']=='Success'&&is_array($data['new'])){unset($data['status']);$this->keydata=array_merge($this->keydata,$data['new']);$this->updateLocalKey($this->keydata);returntrue;}returnfalse;}catch(Exception$e){}}returnfalse;}publicfunctionisValidLicenseKey($licenseKey){if(is_string($licenseKey)||is_numeric($licenseKey)){$pattern='/^[0-9a-zA-Z\\-_]{10,}$/';return(bool)preg_match($pattern,$licenseKey);}returnfalse;}privatefunctiongetWhmcsNetKey(){$key=$this->getKeyData('whmcsnetkey');if(!$key){$key='f4e0cdeba94d4fd5377d20d895ee5600dfc03776';}return$key;}publicfunctionhashMessage($value){$hashKey=$this->getWhmcsNetKey();$obfuscatedLicenseKey=sha1($this->getLicenseKey());$hashable=$obfuscatedLicenseKey.$value.$hashKey;$hmac=hash_hmac('sha256',$hashable,$hashKey);return$obfuscatedLicenseKey.'|'.$value.'|'.$hmac;}publicfunctiongetValueFromHashMessage($message){if(!$this->isValidHashMessage($message)){returnnull;}$parts=explode('|',$message);return$parts[1];}publicfunctionisValidHashMessage($message){$parts=explode('|',$message);if(count($parts)<3){returnfalse;}$hashKey=$this->getWhmcsNetKey();$obfuscatedLicenseKey=array_shift($parts);$hmacGiven=array_pop($parts);$hashable=$obfuscatedLicenseKey.implode('',$parts).$hashKey;$hmacCalculated=hash_hmac('sha256',$hashable,$hashKey);if($hmacGiven!==$hmacCalculated){returnfalse;}returntrue;}}?>
NEW Robots – New option for individual pages to control search engine crawling permissions with “Allow” and “Disallow” settings – Case #951.
FIX Fixed an issue where text was not wrapping correctly on the “Tickets”, “View Ticket”, and “My Emails” pages – Case #924.
FIX Other minor appearance fixes.
Order Process
NEW Compatibility with WHMCS 8.11.x.
NEW Show “One Time” cycle – New setting for the “Products” page to display a “One Time” label under the price for one-time products – Case #930.
NEW Enhanced Free Domain Display – New feature for the “Configure Product Domain” page that clearly displays free domain offers, identifying eligible TLDs and billing periods, with visible discounts upon domain search – Case #925.
NEW Product Comparison – New “section type” feature enables you to create product comparison tables for easy side-by-side comparison of products – Case #404.
NEW Graphics Color Scheme – Default graphics now automatically update to match your selected style color scheme. Previously, graphics stayed blue no matter what color you chose – Case #754.
NEW Include WHMCS Pages in Sitemap – New settings for sitemap that enables adding WHMCS pages like Product Groups, Announcements, Knowledgebase, and Download to the sitemap, ensuring comprehensive coverage and improved SEO – Case #767.
NEW NGINX – Added a possible compatibility with NGINX server type.
Improvements Added gradient variables to illustrations. Now, changing theme color variables dynamically updates gradients in illustrations – Case #762.
FIX Updated “Order Now” buttons for Market Connect products while using Lagom WHMCS One Step Order Form to properly redirect users to the product configuration step, ensuring essential setup is completed before checkout – Case #752.
FIX Fixed background colors for Banner section for all styles and colors, and added relevant variables for the section’s gradients – Case #669.
FIX Corrected the display of USD currency values of 1,000 and higher to match the “1,234.56” number format – Case #764.