分类: 其它系统

  • WHMCS 主题Lagom Theme 2.3.0 正式版已经出来了

    WHMCS 主题Lagom Theme 2.3.0 正式版已经出来了,在这个版本,rsstudio更改了授权认证的方式,所以破解版Nulled要晚一点才能出来,请大家耐心等待,这里先放一些原始版本给大家。

    Lagom WHMCS Client Theme By RSStudio V2.3.0

    这个是主题

    Lagom WHMCS Website Builder V1.1.0

    Website Builder具有更高的自定义功能,提供了很多现成的页面,如果你想让你的whmcs与众不同,那么推荐安装。

    Lagom Client Notifications v1.2.0

    Lagom通知中心模板

    Lagom Email Template v1.1.4 

    Lagom邮件模板,可能让你发给用户的邮件样式更专业和好看。

    由于授权方式的改变,相关破解开心版Nulled版本会稍候再更新给大家,请大家稍候。

  • WHMCS最新Telegram通知插件

    收到订单总是不知道?客户付款了没通知?用户提交工单了没注意?Oneman没有人专门盯着WHMCS总是会有这样的问题发生。如何不让你与客户失之交臂呢? 快使用这款Tg通知插件吧。

    Telegram通知插件 for WHMCS
    Telegram Notifications 是一个 WHMCS 插件,允许您在 WHMCS 安装中发生各种事件时,向指定的 Telegram 频道或群组发送实时通知。该插件配置灵活,安装简单。

    功能

    • 新客户注册时发送通知
    • 发票支付时发送通知
    • 新支持工单打开时发送通知
    • 用户回复支持工单时发送通知
    • 通过 WHMCS 管理面板轻松配置

    安装

    1. 下载插件
    2. 上传插件:
      • telegram_notifications 文件夹上传到 WHMCS 安装目录的 modules/addons/ 文件夹下。

    1. 激活插件:
      • 登录到 WHMCS 管理面板。
      • 进入 设置 > 插件模块
      • 找到 Telegram Notifications,点击 激活 按钮。
    1. 配置插件:
      • 激活后,点击 配置 来设置您的 Telegram 机器人 Token、聊天 ID,并选择您想启用的通知。

    配置

    • Bot Token:
      通过 Telegram 上的 BotFather 创建一个新的机器人来获得 Bot Token。
    • Chat ID:
      获取您希望接收通知的聊天 ID。您可以通过向机器人发送消息并使用工具(如 get_id_bot)来获取聊天 ID。
    • 启用通知:
      您可以通过插件设置中的复选框启用或禁用特定的通知(例如:ClientAdd、InvoicePaid、TicketOpen、TicketUserReply)。

    使用

    配置完成后,插件会自动在 WHMCS 中选定的事件发生时向指定的 Telegram 聊天发送通知。您可以实时监控新客户注册、发票支付和支持工单的活动。

    文件

    • hooks.php:包含 WHMCS 钩子,用于根据事件触发通知。
    • telegram_notifications.php:包含向 Telegram 发送消息的核心逻辑及配置管理。
    • whmcs.json:定义插件的配置选项和元数据。

    效果

    配置完成后,当有用户注册,下单,或者工单时,会有以下通知。

  • WHMCS的 USDT TRC20 支付接口程序

    本插件只支持 TRC-20 USDT 转账交易,系统可完成自动化分配地址,入账等操作,配置简单,无需第三方支付平台中转,所有交易直达您的私人账户。

    环境需求

    1. PHP 7.2 or greater.
    2. WHMCS 8.1 or greater. (WHMCS 7 暂未测试)

    安装

    下载附件过后请按照项目目录结构将文件分别复制到 includes/hooks 和 modules/gateways 目录。

    并在 WHMCS System Setting -> Payment Gateways -> All Payment Gateways  启用扩展,并在 System Setting -> Payment Gateways -> Manage Existing Gateways 中配置相关信息。 请注意 Addresses 需要每行一个,为了保证支付效率,请根据自己的订单数量准备 USDT 地址。通常而言 TRC 20 交易会在半个小时内确认并完成交易。

    运行流程

    当用户创建并选择使用 USDT 支付时,扩展程序会从你后台填写的 USDT 地址池中随机选择一个空闲地址分配给用,有效时间默认为 30 分钟(如果更改过默认值则为您更改的时间间隔),同时前台会发起异步请求后台获取支付状态,如果地址有效期即将过期那么后台会为该地址续期,直到用户关闭页面后由 cron job 终止关联关系或支付完成。

    ​ 系统默认会在前台页面页面每 15 秒发起一次查询并确认订单情况,如果完成支付那么会标记订单支付完成并刷新账单页面。如果用户关闭了账单页面,那么会伴随您设置的 cron 任务频率查询订单状况并标记支付情况。当订单支付完成后系统默认会释放当前地址并等待下一次交易。如果用户部分交易那么会更新账单金额,并续期当前地址,等待支付完成。

  • WHMCS 最新版 8.10-8.12+ 破解补丁 License.php

    之前的破解补丁打开后台首页会报一个 getRegistrationDate Not found,使用这个最新的就好了。加了一个返回 getRegistrationDate 的方法。

    <?php
    namespace WHMCS;
    
    class License
    {
    	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;
    
    	public function checkFile($value)
    	{
    		if ($value != 'a896faf2c31f2acd47b0eda0b3fd6070958f1161') {
    			throw new Exception\Fatal('File version mismatch. Please contact support.');
    		}
    
    		return $this;
    	}
    
    	public function setLicenseKey($licenseKey)
    	{
    		$this->licensekey = $licenseKey;
    		return $this;
    	}
    
    	public function setLocalKey($localKey)
    	{
    		$this->decodeLocal($localKey);
    		return $this;
    	}
    	
    	public function getRegistrationDate(){
    	    return "";
    	}
    
    	public function setSalt($version, $hash)
    	{
    		if (empty($version) || empty($hash)) {
    			throw new Exception('Unable to generate licensing salt');
    		}
    
    		$this->salt = sha1(sprintf('WHMCS%s%s%s', $version, '|-|', $hash));
    		return $this;
    	}
    
    	public function useInternalValidationMirror()
    	{
    		$this->useInternalLicensingMirror = true;
    		return $this;
    	}
    
    	protected function getHosts()
    	{
    		if ($this->useInternalLicensingMirror) {
    			return self::STAGING_LICENSE_API_HOSTS;
    		}
    
    		return self::LICENSE_API_HOSTS;
    	}
    
    	public function getLicenseKey()
    	{
    		return $this->licensekey;
    	}
    
    	protected function getHostDomain()
    	{
    		$domain = defined('WHMCS_LICENSE_DOMAIN') ? WHMCS_LICENSE_DOMAIN : '';
    		if (empty($domain) || $domain == '-') {
    			throw new Exception('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;
    	}
    
    	protected function getHostIP()
    	{
    		$ip = defined('WHMCS_LICENSE_IP') ? WHMCS_LICENSE_IP : '';
    		$this->debug('Host IP: ' . $ip);
    		return $ip;
    	}
    
    	protected function getHostDir()
    	{
    		$directory = defined('WHMCS_LICENSE_DIR') ? WHMCS_LICENSE_DIR : '';
    		$this->debug('Host Directory: ' . $directory);
    		return $directory;
    	}
    
    	private function getSalt()
    	{
    		return $this->salt;
    	}
    
    	protected function isLocalKeyValidToUse()
    	{
    		$licenseKey = $this->getKeyData('key');
    		if (empty($licenseKey) || $licenseKey != $this->licensekey) {
    			throw new Exception('License Key Mismatch in Local Key');
    		}
    
    		$originalcheckdate = $this->getCheckDate();
    		$localmax = Carbon::now()->startOfDay()->addDays(2);
    
    		if ($originalcheckdate->gt($localmax)) {
    			throw new Exception('Original check date is in the future');
    		}
    	}
    
    	protected function hasLocalKeyExpired()
    	{
    		$originalCheckDate = $this->getCheckDate();
    		$localExpiryMax = Carbon::now()->startOfDay()->subDays($this->localkeydays);
    		if (!$originalCheckDate || $originalCheckDate->lt($localExpiryMax)) {
    			throw new Exception('Original check date is outside allowed validity period');
    		}
    	}
    
    	protected function buildPostData()
    	{
    		$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());
    		return array('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)));
    	}
    
    	public function isUnlicensed()
    	{
    		if ($this->getLicenseKey() == static::UNLICENSED_KEY) {
    			return true;
    		}
    
    		return false;
    	}
    
    	public function validate($forceRemote = false)
    	{
    		if (!$forceRemote && $this->hasLocalKey()) {
    			try {
    				$this->isLocalKeyValidToUse();
    				$this->hasLocalKeyExpired();
    				$this->validateLocalKey();
    				$this->debug('Local Key Valid');
    				return true;
    			}
    			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')) {
    			throw new Exception('Required function base64_decode is not available');
    		}
    
    		if ($response) {
    			try {
    				$results = $this->processResponse($response);
    
    				if ($results['hash'] != sha1('WHMCSV5.2SYH' . $postfields['check_token'])) {
    					throw new Exception('Invalid hash check token');
    				}
    
    				$this->setKeyData($results)->updateLocalKey($results)->debug('Remote license check successful');
    				return true;
    			}
    			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');
    					return true;
    				}
    
    				$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)) {
    			throw new Exception('CURL Error: ' . $this->lastCurlError);
    		}
    
    		throw new Exception\Http\ConnectionError();
    	}
    
    	private function callHomeLoop($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());
    			}
    		}
    
    		return false;
    	}
    
    	protected function callHome($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);
    	}
    
    	private function getVerifyUrl($host)
    	{
    		return 'https://' . $host . '/1.1/verify';
    	}
    
    	private function validateCurlIsAvailable()
    	{
    		$curlFunctions = array('curl_init', 'curl_setopt', 'curl_exec', 'curl_getinfo', 'curl_error', 'curl_close');
    
    		foreach ($curlFunctions as $function) {
    			if (!Environment\Php::isFunctionAvailable($function)) {
    				throw new Exception('Required function ' . $function . ' is not available');
    			}
    		}
    	}
    
    	protected function makeCall($url, $query_string, $timeout = 5)
    	{
    		$Arr = explode('&', $query_string );
    		foreach( $Arr as $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;
    	}
    
    	private function processResponse($data)
    	{
    		return $data;
    	}
    
    	private function parseSignedResponse($response, $publicKey)
    	{
    		if ($this->useInternalLicensingMirror) {
    			$data = json_decode($response, true);
    			if (is_null($data) || !is_array($data)) {
    				throw new Exception('Internal licensing mirror response could not be decoded');
    			}
    
    			return $data;
    		}
    
    		$data = explode(':', $response, 2);
    
    		if (empty($data[1])) {
    			throw new Exception('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]))) {
    					throw new Exception('Invalid license signature');
    				}
    			}
    			catch (\Exception $e) {
    				throw new Exception('Invalid license signature');
    			}
    		}
    
    		$data = strrev($data[0]);
    		$data = base64_decode($data);
    		$data = json_decode($data, true);
    
    		if (empty($data)) {
    			throw new Exception('Invalid license data structure');
    		}
    
    		return $data;
    	}
    
    	private function updateLocalKey($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');
    	}
    
    	public function forceRemoteCheck()
    	{
    		return $this->validate(true);
    	}
    
    	private function decodeLocal($localkey = '')
    	{
    		$this->debug('Decoding local key');
    
    		if (!$localkey) {
    			$this->debug('No local key provided');
    			return false;
    		}
    
    		$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');
    			return false;
    		}
    
    		$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');
    			return false;
    		}
    
    		$this->setKeyData($localKeyData);
    		$this->debug('Local Key Decoded Successfully');
    		return true;
    	}
    
    	protected function isRunningInCLI()
    	{
    		return php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR']);
    	}
    
    	protected function hasLocalKey()
    	{
    		return !is_null($this->keydata);
    	}
    
    	protected function validateLocalKey()
    	{
    		if ($this->getKeyData('status') != 'Active') {
    			throw new Exception('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 {
    				throw new Exception('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');
    			}
    			else if (!trim($this->getKeyData('validips'))) {
    				$this->debug('No Valid IPs returned by license check - Cloud Based License - Skipping Local Validation of IP');
    			}
    			else if ($this->isValidIP($ip)) {
    				$this->debug('IP Validated Successfully');
    			}
    			else {
    				throw new Exception('Invalid IP');
    			}
    		}
    
    		if ($this->isValidDir($this->getHostDir())) {
    			$this->debug('Directory Validated Successfully');
    		}
    		else {
    			throw new Exception('Invalid directory');
    		}
    	}
    
    	private function isValidDomain($domain)
    	{
    		$validdomains = $this->getArrayKeyData('validdomains');
    		return in_array($domain, $validdomains);
    	}
    
    	private function isValidIP($ip)
    	{
    		$validips = $this->getArrayKeyData('validips');
    		return in_array($ip, $validips);
    	}
    
    	private function isValidDir($dir)
    	{
    		$validdirs = $this->getArrayKeyData('validdirs');
    		return in_array($dir, $validdirs);
    	}
    
    	public function getBanner()
    	{
    		$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';
    			}
    			else if ($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 '';
    	}
    
    	private function revokeLocal()
    	{
    		\App::self()->set_config('License', '');
    	}
    
    	public function getKeyData($var)
    	{
    		return isset($this->keydata[$var]) ? $this->keydata[$var] : '';
    	}
    
    	private function setKeyData($data)
    	{
    		$this->keydata = $data;
    		return $this;
    	}
    
    	protected function getArrayKeyData($var)
    	{
    		$listData = array();
    		$rawData = $this->getKeyData($var);
    
    		if (is_string($rawData)) {
    			$listData = explode(',', $rawData);
    
    			foreach ($listData as $k => $v) {
    				if (is_string($v)) {
    					$listData[$k] = trim($v);
    				}
    				else {
    					throw new Exception('Invalid license data structure');
    				}
    			}
    		}
    		else {
    			if (!is_null($rawData)) {
    				throw new Exception('Invalid license data structure');
    			}
    		}
    
    		return $listData;
    	}
    
    	public function getRegisteredName()
    	{
    		return $this->getKeyData('registeredname');
    	}
    
    	public function getProductName()
    	{
    		return $this->getKeyData('productname');
    	}
    
    	public function getStatus()
    	{
    		return $this->getKeyData('status');
    	}
    
    	public function getSupportAccess()
    	{
    		return $this->getKeyData('supportaccess');
    	}
    
    	protected function getCheckDate()
    	{
    		$checkDate = $this->getKeyData('checkdate');
    
    		if (empty($checkDate)) {
    			return false;
    		}
    
    		return Carbon::createFromFormat('Y-m-d', $checkDate);
    	}
    
    	protected function getLicensedAddons()
    	{
    		$licensedAddons = $this->getKeyData('addons');
    
    		if (!is_array($licensedAddons)) {
    			$licensedAddons = array();
    		}
    
    		return $licensedAddons;
    	}
    
    	public function getActiveAddons()
    	{
    		$licensedAddons = $this->getLicensedAddons();
    		$activeAddons = array();
    
    		foreach ($licensedAddons as $addon) {
    			if ($addon['status'] == 'Active') {
    				$activeAddons[] = $addon['name'];
    			}
    		}
    
    		return $activeAddons;
    	}
    
    	public function isActiveAddon($addon)
    	{
    		return in_array($addon, $this->getActiveAddons()) ? true : false;
    	}
    
    	public function getExpiryDate($showday = false)
    	{
    		$expiry = $this->getKeyData('nextduedate');
    
    		if (!$expiry) {
    			$expiry = 'Never';
    		}
    		else if ($showday) {
    			$expiry = date('l, jS F Y', strtotime($expiry));
    		}
    		else {
    			$expiry = date('jS F Y', strtotime($expiry));
    		}
    
    		return $expiry;
    	}
    
    	public function getLatestPublicVersion()
    	{
    		try {
    			$latestVersion = new Version\SemanticVersion($this->getKeyData('latestpublicversion'));
    		}
    		catch (Exception\Version\BadVersionNumber $e) {
    			$whmcs = \DI::make('app');
    			$latestVersion = $whmcs->getVersion();
    		}
    
    		return $latestVersion;
    	}
    
    	public function getLatestPreReleaseVersion()
    	{
    		try {
    			$latestVersion = new Version\SemanticVersion($this->getKeyData('latestprereleaseversion'));
    		}
    		catch (Exception\Version\BadVersionNumber $e) {
    			$whmcs = \DI::make('app');
    			$latestVersion = $whmcs->getVersion();
    		}
    
    		return $latestVersion;
    	}
    
    	public function getLatestVersion()
    	{
    		$whmcs = \DI::make('app');
    		$installedVersion = $whmcs->getVersion();
    
    		if (in_array($installedVersion->getPreReleaseIdentifier(), array('beta', 'rc'))) {
    			$latestVersion = $this->getLatestPreReleaseVersion();
    		}
    		else {
    			$latestVersion = $this->getLatestPublicVersion();
    		}
    
    		return $latestVersion;
    	}
    
    	public function isUpdateAvailable()
    	{
    		$whmcs = \DI::make('app');
    		$installedVersion = $whmcs->getVersion();
    		$latestVersion = $this->getLatestVersion();
    		return Version\SemanticVersion::compare($latestVersion, $installedVersion, '>');
    	}
    
    	public function getRequiresUpdates()
    	{
    		return $this->getKeyData('requiresupdates') ? true : false;
    	}
    
    	public function getUpdatesExpirationDate()
    	{
    		$expirationDates = array();
    		$licensedAddons = $this->getLicensedAddons();
    
    		foreach ($licensedAddons as $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 '';
    	}
    
    	public function checkOwnedUpdatesForReleaseDate($releaseDate)
    	{
    		if (!$this->getRequiresUpdates()) {
    			return true;
    		}
    
    		try {
    			$updatesExpirationDate = Carbon::createFromFormat('Y-m-d', $this->getUpdatesExpirationDate());
    			$checkDate = Carbon::createFromFormat('Y-m-d', $releaseDate);
    			return $checkDate <= $updatesExpirationDate ? true : false;
    		}
    		catch (\Exception $e) {
    		}
    
    		return false;
    	}
    
    	public function checkOwnedUpdates()
    	{
    		$whmcs = \DI::make('app');
    		$isLicenseValidForVersion = $this->checkOwnedUpdatesForReleaseDate($whmcs->getReleaseDate());
    
    		if (!$isLicenseValidForVersion) {
    			try {
    				$this->forceRemoteCheck();
    				$isLicenseValidForVersion = $this->checkOwnedUpdatesForReleaseDate($whmcs->getReleaseDate());
    			}
    			catch (\Exception $e) {
    			}
    		}
    
    		return $isLicenseValidForVersion;
    	}
    
    	public function getBrandingRemoval()
    	{
    		if (in_array($this->getProductName(), array('Owned License No Branding', 'Monthly Lease No Branding'))) {
    			return true;
    		}
    
    		$licensedAddons = $this->getLicensedAddons();
    
    		foreach ($licensedAddons as $addon) {
    			if ($addon['name'] == 'Branding Removal' && $addon['status'] == 'Active') {
    				return true;
    			}
    		}
    
    		return false;
    	}
    
    	private function debug($msg)
    	{
    		$this->debuglog[] = $msg;
    		return $this;
    	}
    
    	public function getDebugLog()
    	{
    		return $this->debuglog;
    	}
    
    	public function getUpdateValidityDate()
    	{
    		return new \DateTime();
    	}
    
    	public function isClientLimitsEnabled()
    	{
    		return (bool) $this->getKeyData('ClientLimitsEnabled');
    	}
    
    	public function getClientLimit()
    	{
    		$clientLimit = $this->getKeyData('ClientLimit');
    
    		if ($clientLimit == '') {
    			return -1;
    		}
    
    		if (!is_numeric($clientLimit)) {
    			$this->debug('Invalid client limit value in license');
    			return 0;
    		}
    
    		return (int) $clientLimit;
    	}
    
    	public function getTextClientLimit()
    	{
    		$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;
    	}
    
    	public function getNumberOfActiveClients()
    	{
    		return (int) get_query_val('tblclients', 'count(id)', 'status=\'Active\'');
    	}
    
    	public function getTextNumberOfActiveClients(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;
    	}
    
    	public function getClientBoundaryId()
    	{
    		$clientLimit = $this->getClientLimit();
    
    		if ($clientLimit < 0) {
    			return 0;
    		}
    
    		return (int) get_query_val('tblclients', 'id', 'status=\'Active\'', 'id', 'ASC', (int) $clientLimit . ',1');
    	}
    
    	public function isNearClientLimit()
    	{
    		$clientLimit = $this->getClientLimit();
    		$numClients = $this->getNumberOfActiveClients();
    		if ($numClients < 1 || $clientLimit < 1) {
    			return false;
    		}
    
    		$percentageBound = 250 < $clientLimit ? 0.050000000000000003 : 0.10000000000000001;
    		return $clientLimit * (1 - $percentageBound) <= $numClients;
    	}
    
    	public function isClientLimitsAutoUpgradeEnabled()
    	{
    		return (bool) $this->getKeyData('ClientLimitAutoUpgradeEnabled');
    	}
    
    	public function getClientLimitLearnMoreUrl()
    	{
    		return $this->getKeyData('ClientLimitLearnMoreUrl');
    	}
    
    	public function getClientLimitUpgradeUrl()
    	{
    		return $this->getKeyData('ClientLimitUpgradeUrl');
    	}
    
    	protected function getMemberPublicKey()
    	{
    		$publicKey = Config\Setting::getValue('MemberPubKey');
    
    		if ($publicKey) {
    			$publicKey = decrypt($publicKey);
    		}
    
    		return $publicKey;
    	}
    
    	protected function setMemberPublicKey($publicKey = '')
    	{
    		if ($publicKey) {
    			$publicKey = encrypt($publicKey);
    			Config\Setting::setValue('MemberPubKey', $publicKey);
    		}
    
    		return $this;
    	}
    
    	public function encryptMemberData(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) {
    					throw new Exception('Could not perform RSA encryption');
    				}
    				else {
    					$cipherText = base64_encode($cipherText);
    				}
    			}
    			catch (\Exception $e) {
    				$this->debug('Failed to encrypt member data');
    			}
    		}
    
    		return $cipherText;
    	}
    
    	public function getClientLimitNotificationAttributes()
    	{
    		if (!$this->isClientLimitsEnabled() || !$this->isNearClientLimit()) {
    			return null;
    		}
    
    		$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) {
    			}
    			else if ($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;
    			}
    		}
    		else if ($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.';
    		}
    		else if ($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;
    	}
    
    	protected function buildMemberData()
    	{
    		return array('licenseKey' => $this->getLicenseKey(), 'activeClientCount' => $this->getNumberOfActiveClients());
    	}
    
    	public function getEncryptedMemberData()
    	{
    		return $this->encryptMemberData($this->buildMemberData());
    	}
    
    	protected function getUpgradeUrl($host)
    	{
    		return 'https://' . $host . '/' . self::LICENSE_API_VERSION . '/upgrade';
    	}
    
    	public function makeUpgradeCall()
    	{
    		$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)) {
    					return false;
    				}
    
    				if ($data['status'] == 'Success' && is_array($data['new'])) {
    					unset($data['status']);
    					$this->keydata = array_merge($this->keydata, $data['new']);
    					$this->updateLocalKey($this->keydata);
    					return true;
    				}
    
    				return false;
    			}
    			catch (Exception $e) {
    			}
    		}
    
    		return false;
    	}
    
    	public function isValidLicenseKey($licenseKey)
    	{
    		if (is_string($licenseKey) || is_numeric($licenseKey)) {
    			$pattern = '/^[0-9a-zA-Z\\-_]{10,}$/';
    			return (bool) preg_match($pattern, $licenseKey);
    		}
    
    		return false;
    	}
    
    	private function getWhmcsNetKey()
    	{
    		$key = $this->getKeyData('whmcsnetkey');
    
    		if (!$key) {
    			$key = 'f4e0cdeba94d4fd5377d20d895ee5600dfc03776';
    		}
    
    		return $key;
    	}
    
    	public function hashMessage($value)
    	{
    		$hashKey = $this->getWhmcsNetKey();
    		$obfuscatedLicenseKey = sha1($this->getLicenseKey());
    		$hashable = $obfuscatedLicenseKey . $value . $hashKey;
    		$hmac = hash_hmac('sha256', $hashable, $hashKey);
    		return $obfuscatedLicenseKey . '|' . $value . '|' . $hmac;
    	}
    
    	public function getValueFromHashMessage($message)
    	{
    		if (!$this->isValidHashMessage($message)) {
    			return null;
    		}
    
    		$parts = explode('|', $message);
    		return $parts[1];
    	}
    
    	public function isValidHashMessage($message)
    	{
    		$parts = explode('|', $message);
    
    		if (count($parts) < 3) {
    			return false;
    		}
    
    		$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) {
    			return false;
    		}
    
    		return true;
    	}
    }
    
    
    ?>
    
  • Lagom WHMCS Client Theme 2.2.8 Nulled 开心版破解版

    Client Area
    • NEW Compatibility with WHMCS 8.11.x
    • 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.
    • FIX Other minor appearance fixes.
  • Lagom Website Builder By RSStudio V1.0.4 Nulled 开心版破解版

    Compatible with Lagom WHMCS Client Theme 2.2.8 and later

    • NEW Compatibility with WHMCS 8.11.x
    • FIX Fixed an issue when the sitemap was generated although “Enable Sitemap” feature was disabled – Case #806.
    • FIX Other minor appearance fixes.
  • Lagom WHMCS Client Theme By RSStudioLagom 主题激活

    有些朋友下载主题后发现激活不了,可以试一下手动激活的方法。

    替换license.php文件 ,位置 /modules/addons/RSThemes/src/Template/License.php

    也可附件下载 ,内容和这个是一样的。

    <?php
    namespace RSThemes\Template;
    
    /**
     * Class License
     * @package RSThemes\Template
     */
    class License
    {
        /** @var string $licenseKey */
        public $licenseKey = "";
        /** @var int $licenseFailDays */
        public $licenseFailDays = 30;
        /** @var int $licenseFailWarningDays */
        public $licenseFailWarningDays = 3;
        /** @var Template $template */
        public $template = NULL;
        /** @var string $templateName */
        public $templateName = NULL;
        /** @var bool $forceRemoteCheck */
        public $forceRemoteCheck = false;
        /** @var string $licenseKeyName */
        private $licenseKeyName = NULL;
        /** @var string $licenseSecretKey */
        private $licenseSecretKey = NULL;
        /** @var string $licenseConfigKey */
        private $licenseConfigKey = NULL;
        /** @var array $lastRemoteCheck */
        private $activationCache = [];
        /** @var array $licenseDetails */
        private $licenseDetails = ["status" => "Active", "service_status" => "Active", "license_status" => "Active", "nextduedate" => "2099-10-01", "version" => "1.0.0", "fullversion" => "1.0.0", "lastRemoteChecked" => "2099-10-01", "lastRemoteCheckedFail" => "", "lastRemoteCheckedSuccess" => "2099-10-01", "regdate" => "2023-10-01", "first_payment_amount" => "$0", "recuring_amount" => "$0", "payment_method" => "Babiato", "warningShowDate" => "", "deactivationDate" => "2099-10-01"];
        /** @var array $rawLicenseDetails */
        private $rawLicenseDetails = NULL;
        /** @var string $licenseEncoded */
        private $licenseEncoded = NULL;
        /** @var string $licenseWarningKey */
        private $licenseWarningKey = NULL;
        /** @var string $licenseWarningMessage */
        private $licenseWarningMessage = NULL;
        /** @var bool $debug */
        private $debug = false;
        /**
         * @var string
         */
        private $checkLicenseHour = NULL;
        /** @var string $licenseServerUrl */
        public static $licenseServerUrl = "https://rsstudio.net/my-account/";
        public function __construct($licenseKeyName, $licenseSecretKey, $template)
        {
            $this->loadLicenseHour($licenseKeyName);
            $this->licenseKeyName = $licenseKeyName;
            $this->licenseSecretKey = $licenseSecretKey;
            $this->template = $template;
            $this->licenseConfigKey = sprintf("%s-data", $licenseKeyName);
            $this->licenseKey = (new \RSThemes\Models\Configuration())->getConfig($licenseKeyName);
            $this->licenseWarningKey = sprintf("%s-warning", $licenseKeyName);
            $this->licenseWarningMessage = (new \RSThemes\Models\Configuration())->getConfig($this->licenseWarningKey);
            $this->templateName = $this->template->getMainName();
            $this->licenseEncoded = (new \RSThemes\Models\Configuration())->getConfig($this->licenseConfigKey);
            $this->rawLicenseDetails = $this->licenseDetails;
            $this->prepareLicense();
        }
        private function loadLicenseHour($licenseKeyName)
        {
            $keyName = sprintf("%s-hour", $licenseKeyName);
            $hour = (new \RSThemes\Models\Configuration())->getConfig($keyName);
            if (strlen($hour) == 0) {
                $hour = rand(4, 23) . ":" . str_pad(rand(2, 59), 2, "0", STR_PAD_LEFT);
                (new \RSThemes\Models\Configuration())->saveConfig($keyName, $hour);
            }
            $this->checkLicenseHour = $hour;
        }
        private function prepareLicense()
        {
            if (0 < strlen($this->licenseEncoded)) {
                $this->loadLicense();
            }
            if ($this->licenseDetails["service_status"] == "Active" && isset($this->licenseDetails["deactivationDate"]) && strlen($this->licenseDetails["deactivationDate"]) && $this->licenseDetails["deactivationDate"] < date("Y-m-d")) {
                $this->deactivateTemplate();
            }
            if ($this->licenseDetails["service_status"] == "Active" && $this->remoteCheck()) {
                $this->reloadRemote();
            }
            if ($this->debug === true) {
                echo "<pre>";
                var_dump($this->licenseDetails);
                echo "</pre>";
                exit;
            }
        }
        private function loadLicense()
        {
            $result = self::decodeLicense($this->licenseEncoded, $this->licenseSecretKey);
            if ($result) {
                $this->licenseDetails = [];
                foreach ($this->rawLicenseDetails as $key => $value) {
                    $this->licenseDetails[$key] = isset($result[$key]) ? $result[$key] : $this->rawLicenseDetails[$key];
                }
            } else {
                $this->deactivateTemplate();
            }
        }
        public function deactivateTemplate()
        {
            if ((new \RSThemes\Models\Configuration())->getConfig("OrderFormTemplate") == $this->templateName) {
                (new \RSThemes\Models\Configuration())->saveConfig("OrderFormTemplate", "standard_cart");
            }
            if ((new \RSThemes\Models\Configuration())->getConfig("Template") == $this->templateName) {
                (new \RSThemes\Models\Configuration())->saveConfig("Template", "six");
            }
            (new \RSThemes\Models\Configuration())->removeConfig($this->licenseConfigKey);
            $this->licenseDetails = $this->rawLicenseDetails;
            $this->licenseEncoded = "";
        }
        private function remoteCheck()
        {
            if (strlen($this->licenseKey) <= 0) {
                return false;
            }
            if ($this->forceRemoteCheck === true) {
                return true;
            }
            if ($this->licenseDetails["lastRemoteChecked"] != date("Y-m-d") && strtotime($this->checkLicenseHour) < strtotime(date("H:i"))) {
                return true;
            }
            return false;
        }
        private function reloadRemote($activation = false)
        {
            $details = self::loadRemoteLicense($this->licenseKey, $this->template->getVersion(), $this->templateName);
            if (isset($details["lastRemoteChecked"])) {
                $this->licenseDetails["lastRemoteChecked"] = $details["lastRemoteChecked"];
                $this->saveLicenseDetails($this->licenseDetails);
            }
            if (isset($details["lastRemoteCheckedSuccess"])) {
                $this->licenseDetails["lastRemoteCheckedSuccess"] = $details["lastRemoteCheckedSuccess"];
                $this->saveLicenseDetails($this->licenseDetails);
            }
            if (isset($details["lastRemoteCheckedFail"])) {
                $this->licenseDetails["lastRemoteCheckedFail"] = $details["lastRemoteCheckedFail"];
                $this->saveLicenseDetails($this->licenseDetails);
            }
            if (isset($details["license_status"]) && in_array($details["license_status"], ["Active", "Suspended", "Expired"])) {
                self::logDetails("RSThemes", "reloadRemote - 1", "License Active");
                $this->saveLicenseDetails($details);
            }
            if (isset($details["license_status"]) && $details["license_status"] == "Cancelled") {
                self::logDetails("RSThemes", "reloadRemote - 2", "License Cancelled - Template Deactivated");
                if ($activation === false) {
                    $this->setWarningMessage("deactivated.cancelled", $this->licenseKey);
                }
                $this->deactivateTemplate();
            }
            if (isset($details["license_status"]) && $details["license_status"] == "Banned") {
                self::logDetails("RSThemes", "reloadRemote - 2", "License Cancelled - Template Deactivated");
                if ($activation === false) {
                    $this->setWarningMessage("deactivated.cancelled", $this->licenseKey);
                }
                $this->deactivateTemplate();
            }
            if (isset($details["license_status"]) && $details["license_status"] == "Unknown") {
                if ($this->licenseDetails["license_status"] == "Active") {
                    self::logDetails("RSThemes", "reloadRemote - 3", "License Unknown, warning dates set. ");
                    $this->setWarning();
                } else {
                    self::logDetails("RSThemes", "reloadRemote - 4", "License Unknown - Template Deactivated");
                    if ($activation === false) {
                        $this->setWarningMessage("deactivated.unknown", $this->licenseKey);
                    }
                    $this->deactivateTemplate();
                }
            }
            if (isset($details["license_status"]) && $details["license_status"] == "Invalid") {
                if ($this->licenseDetails["license_status"] == "Active") {
                    self::logDetails("RSThemes", "reloadRemote - 5", "License Invalid, warning dates set. ");
                    $this->setWarning();
                } else {
                    self::logDetails("RSThemes", "reloadRemote - 6", "License Invalid - Template Deactivated");
                    if ($activation === false) {
                        $this->setWarningMessage("deactivated.invalid", $this->licenseKey);
                    }
                    $this->deactivateTemplate();
                }
            }
            $this->syncExtensions($details);
            return $details;
        }
        private function saveLicenseDetails($remoteDetails)
        {
            $this->licenseDetails = [];
            foreach ($this->rawLicenseDetails as $key => $value) {
                $this->licenseDetails[$key] = isset($remoteDetails[$key]) ? $remoteDetails[$key] : $this->rawLicenseDetails[$key];
            }
            (new \RSThemes\Models\Configuration())->saveConfig($this->licenseConfigKey, self::encodeLicense($this->licenseDetails, $this->licenseSecretKey));
        }
        private function setWarningMessage($string, $key)
        {
            $this->cleanWarningMessage();
            (new \RSThemes\Models\Configuration())->saveConfig($this->licenseWarningKey, sprintf($this->getMessagePart($string), $key));
        }
        private function cleanWarningMessage()
        {
            (new \RSThemes\Models\Configuration())->removeConfig($this->licenseWarningKey);
        }
        private function getMessagePart($msg, $part = 1)
        {
            $message = explode("|", \RSThemes\Helpers\Messages::get($msg));
            if (count($message) == 0) {
                return $msg;
            }
            if (count($message) == 1) {
                return $message[0];
            }
            if (isset($message[$part])) {
                return $message[$part];
            }
            return $msg;
        }
        private function setWarning()
        {
            if (strlen($this->licenseDetails["warningShowDate"]) == 0) {
                $this->licenseDetails["warningShowDate"] = date("Y-m-d", strtotime("+" . $this->licenseFailWarningDays . " days"));
            }
            if (strlen($this->licenseDetails["deactivationDate"]) == 0) {
                $this->licenseDetails["deactivationDate"] = date("Y-m-d", strtotime("+" . $this->licenseFailDays . " days"));
            }
            $this->saveLicenseDetails($this->licenseDetails);
        }
        public static function logDetails($module = "", $method = "", $message = "", $details = [])
        {
        }
        public static function downloadDBLog()
        {
        }
        public static function downloadFileLog()
        {
        }
        private static function decodeLicense($encoded, $secretKey)
        {
            $key = str_replace("\n", "", $encoded);
            $encoded = substr($key, 0, strlen($key) - 32);
            $md5hash = substr($key, strlen($key) - 32);
            if ($md5hash == md5($encoded . $secretKey)) {
                $encoded = strrev($encoded);
                $encoded = substr($encoded, 32);
                $encoded = base64_decode($encoded);
                return unserialize($encoded);
            }
            return false;
        }
        private static function encodeLicense($details, $secretKey)
        {
            $data = serialize($details);
            $data = base64_encode($data);
            $data = md5(date("Ymd") . $secretKey) . $data;
            $data = strrev($data);
            $data = $data . md5($data . $secretKey);
            $data = wordwrap($data, 80, "\n", true);
            return $data;
        }
        private static function loadRemoteLicense($licenseKey, $version, $templateName)
        {
            if (empty($_SERVER["SERVER_NAME"])) {
                $results = [];
                $results["emptyServerName"] = true;
                return $results;
            }
            $licenseFields = ["licensekey" => $licenseKey, "domain" => self::getDomain(), "ip" => "", "dir" => self::getDirPath(), "version" => $version, "cron" => \RSThemes\Helpers\AddonHelper::isCliMode(), "template" => $templateName];
            $query = "";
            foreach ($licenseFields as $k => $v) {
                $query .= $k . "=" . urlencode($v) . "&";
            }
            $results = [];
            $results["lastRemoteChecked"] = date("Y-m-d");
            if (!empty($licenseKey)) {
                $licenseFields["ip"] = $_SERVER['SERVER_ADDR'];
                // Assign each element from $array
                $results["lastRemoteChecked"] = date("Y-m-d");
                $results["status"] = "Active";
                $results["service_status"] = "Active";
                $results["license_status"] = "Active";
                $results["registeredname"] = "Babiato";
                $results["email"] = "Babiato";
                $results["serviceid"] = "130891";
                $results["productid"] = "19";
                $results["productname"] = "Single Domain";
                $results["version"] = $version;
                $results["fullversion"] = "Lagom " . $version;
                $results["regdate"] = date("Y-m-d");
                $results["nextduedate"] = "2924-09-16";
                $results["billingcycle"] = "Annually";
                $results["first_payment_amount"] = "\$129.00";
                $results["recuring_amount"] = "\$129.00";
                $results["payment_method"] = "PayPal";
    
                $results["validdomain"] = self::getDomain() . ",www." . self::getDomain();
                $results["extensions"] = "Client Notifications,Promotion Manager,Website Builder,Email Template,Custom Code,Support Hours";
                $results["validdirectory"] = self::getDirPath();
                $results["configoptions"] = "domain_conflict|Allow Domain Conflict=|dir_conflict|Allow Directory Conflict=|ip_conflict|Allow IP Conflict=";
                $results["domainconnflict"] = "no";
                $results["ipconflict"] = "no";
                $results["dirconflict"] = "no";
                $results["lastRemoteCheckedSuccess"] = date("Y-m-d");
                $results["remoteChecked"] = "1";
                
                self::logDetails("RSThemes", "checkRemoteLicense-3", $licenseFields, $results);
                return $results;
            }
            $results["lastRemoteCheckedFail"] = date("Y-m-d");
            $results["status"] = "Active";
            $results["service_status"] = "Active";
            $results["license_status"] = "Active";
            $results["message"] = "Curl extension not found!";
            $results["messagecode"] = "errors.9";
            self::logDetails("RSThemes", "checkRemoteLicense-1", $licenseFields, $results);
            return $results;
        }
        private static function getDomain()
        {
            $configName = sprintf("%s-%s-%s", "RSThemes", "license", "domain");
            $domain = $_SERVER["SERVER_NAME"];
            if (0 < strlen($domain)) {
                (new \RSThemes\Models\Configuration())->saveConfig($configName, $domain);
                return $domain;
            }
            return "";
        }
        private static function getDirPath()
        {
            if (defined("WHMCS_LICENSE_DIR") && 0 < strlen(WHMCS_LICENSE_DIR)) {
                return WHMCS_LICENSE_DIR;
            }
            return str_replace("\\modules\\addons\\RSThemes\\src\\Template", "", str_replace("/modules/addons/RSThemes/src/Template", "", realpath(dirname(__FILE__))));
        }
        private static function checkLogDatabase()
        {
            if (\Illuminate\Database\Capsule\Manager::schema()->hasTable("rstheme_logs")) {
                return true;
            }
            try {
                \Illuminate\Database\Capsule\Manager::schema()->create("rstheme_logs", function ($table) {
                    $table->increments("id");
                    $table->string("name");
                    $table->text("details");
                    $table->timestamps();
                });
                if (\Illuminate\Database\Capsule\Manager::schema()->hasTable("rstheme_logs")) {
                    return true;
                }
                return false;
            } catch (\Exception $exception) {
                return false;
            }
        }
        public function expired()
        {
            if (0 < strlen($this->licenseDetails["nextduedate"])) {
                $dueDateDiff = \Carbon\Carbon::parse($this->licenseDetails["nextduedate"])->diffInDays(\Carbon\Carbon::today(), false);
                return in_array($dueDateDiff, [0, 7, 14, 30]);
            }
        }
        public function getExpiredText()
        {
            $dueDateDiff = \Carbon\Carbon::parse($this->licenseDetails["nextduedate"])->diffInDays(\Carbon\Carbon::today(), false);
            return \RSThemes\Helpers\Messages::get("expired." . $dueDateDiff);
        }
        public function isActive()
        {
            if (in_array($this->licenseDetails["license_status"], ["Active", "Suspended", "Expired"])) {
                return true;
            }
            return false;
        }
        public function getLicenseKey()
        {
            return $this->licenseKey;
        }
        public function details($key)
        {
            return isset($this->licenseDetails[$key]) ? $this->licenseDetails[$key] : "";
        }
        public function getDetails()
        {
            return $this->licenseDetails;
        }
        public function activateLicense($licenseKey)
        {
            $this->cleanWarningMessage();
            self::logDetails("RSThemes", "activateLicense - 1", "Deactivation License before attempting to activate");
            if ((new \RSThemes\Models\Configuration())->getConfig("OrderFormTemplate") == $this->templateName) {
                $this->activationCache["OrderFormTemplate"] = $this->templateName;
            }
            if ((new \RSThemes\Models\Configuration())->getConfig("Template") == $this->templateName) {
                $this->activationCache["Template"] = $this->templateName;
            }
            $this->deactivateTemplate();
            if (strlen($licenseKey) <= 0) {
                self::logDetails("RSThemes", "activateLicense - 2", "Deactivation License - empty key when trying to activate");
                \RSThemes\Helpers\Flash::setFlashMessage("danger", \RSThemes\Helpers\Messages::get("errors.5"));
            } else {
                $this->saveLicenseKey($licenseKey);
                $details = $this->reloadRemote(true);
                if (isset($details["emptyServerName"]) && $details["emptyServerName"]) {
                    return \RSThemes\Helpers\Flash::setFlashMessage("danger", \RSThemes\Helpers\Messages::get("empty_server_name"));
                }
                if ($this->licenseDetails["license_status"] == "Active" && isset($this->activationCache["OrderFormTemplate"])) {
                    (new \RSThemes\Models\Configuration())->saveConfig("OrderFormTemplate", $this->activationCache["OrderFormTemplate"]);
                    unset($this->activationCache["OrderFormTemplate"]);
                }
                if ($this->licenseDetails["license_status"] == "Active" && isset($this->activationCache["Template"])) {
                    (new \RSThemes\Models\Configuration())->saveConfig("Template", $this->activationCache["Template"]);
                    unset($this->activationCache["Template"]);
                }
                if ($this->licenseDetails["license_status"] == "Active") {
                    return \RSThemes\Helpers\Flash::setFlashMessage("success", \RSThemes\Helpers\Messages::get("success.1"));
                }
                if (isset($details["license_status"]) && $details["license_status"] == "Active") {
                    return \RSThemes\Helpers\Flash::setFlashMessage("danger", \RSThemes\Helpers\Messages::get("errors.14"));
                }
                return \RSThemes\Helpers\Flash::setFlashMessage("danger", \RSThemes\Helpers\Messages::get("errors.13"));
            }
        }
        public function saveLicenseKey($licenseKey)
        {
            (new \RSThemes\Models\Configuration())->saveConfig($this->licenseKeyName, $licenseKey);
            $this->licenseKey = $licenseKey;
        }
        public function getLastFullVersion()
        {
            return isset($this->licenseDetails["fullversion"]) ? $this->licenseDetails["fullversion"] : "";
        }
        public function getLastVersion()
        {
            return isset($this->licenseDetails["version"]) ? $this->licenseDetails["version"] : "";
        }
        public function getDashboardMessages()
        {
            $html = "";
            if (0 < strlen($this->licenseDetails["nextduedate"]) && $this->licenseDetails["nextduedate"] != "0000-00-00") {
                $dueDateDiff = \Carbon\Carbon::today()->diffInDays(\Carbon\Carbon::parse($this->licenseDetails["nextduedate"]), false);
                $notShow = false;
                if ($_COOKIE["licenseexp"] == "4ever" || $_COOKIE["licenseexp"] == "1" && 2 < $dueDateDiff) {
                    $notShow = true;
                }
                if (0 <= $dueDateDiff && $dueDateDiff <= 14 && !$notShow) {
                    $html .= "<div class=\"alert alert--outline has-icon alert--border-left alert--license alert--info\"><div class=\"alert__body\">";
                    if ($dueDateDiff == 0) {
                        $html .= str_replace("%days%", $dueDateDiff, \RSThemes\Helpers\Messages::get("warnings.6"));
                        $html = str_replace("<b><span class=\"hidden\">Lagom WHMCS Theme - </span>", "<b>Lagom WHMCS Client Theme Nulled by @looper - ", $html);
                    } else {
                        $html .= str_replace("%days%", $dueDateDiff, \RSThemes\Helpers\Messages::get("warnings.5"));
                        $html = str_replace("<b><span class=\"hidden\">Lagom WHMCS Theme - </span>", "<b>Lagom WHMCS Client Theme Nulled by @looper - ", $html);
                    }
                    $html .= "<div class=\"form-check\"><label class=\"m-b-0x m-t-1x\"><input type=\"checkbox\" name=\"notshow\" data-dont-show class=\"form-checkbox\"><span class=\"form-indicator\"></span><span class=\"form-text\">Do not show again</span></label></div>";
                    $html .= "</div><div class=\"alert__actions\">\n                            <a class=\"btn btn-default\" href=\"https://rsstudio.net/my-account/\" target=\"_blank\">Pay Now</a>\n                            <button class=\"btn btn-default\" data-dismiss=\"alert\" aria-label=\"Close\" type=\"button\">Dismiss</button>\n                            </div>";
                    $html .= "</div>";
                    $html .= "<style>\n                    @font-face {\n                        font-family: \"Material-Design-Iconic-Font\";\n                        src: url(\"https://cdnjs.cloudflare.com/ajax/libs/material-design-iconic-font/2.2.0//fonts/Material-Design-Iconic-Font.woff2?v=2.2.0\") format(\"woff2\"), url(\"https://cdnjs.cloudflare.com/ajax/libs/material-design-iconic-font/2.2.0//fonts/Material-Design-Iconic-Font.woff?v=2.2.0\") format(\"woff\"), url(\"https://cdnjs.cloudflare.com/ajax/libs/material-design-iconic-font/2.2.0//fonts/Material-Design-Iconic-Font.ttf?v=2.2.0\") format(\"truetype\");\n                        font-weight: normal;\n                        font-style: normal;\n                    }\n                    .alert--license {\n                        position: relative;\n                        display: flex;\n                        justify-content: space-between;\n                        align-items: center;\n                        flex-flow: row wrap;\n                        padding: 13px 16px 13px 56px;\n                        margin-bottom: 32px;\n                        border: none;\n                        box-shadow: 0 2px 8px rgba(0,0,0,0.08);\n                        background: #fff;\n                    }\n                    .alert--license.alert--info{\n                        color: #50bfff;\n                        border-color: #50bfff;\n                    }\n                    .alert--license *{\n                        box-sizing: border-box;\n                    }\n                    .alert--license:before{\n                        position: absolute;\n                        top: 50%;\n                        left: 15px;\n                        width: 24px;\n                        height: 24px;                        \n                        margin-top: -12px;\n                        text-align: center;\n                        font-family: Material-Design-Iconic-Font;\n                        font-size: 24px;\n                        line-height: 22px;\n                    }\n                    .alert--license.alert--info:before{\n                        content: \"\\f1f7\";\n                    }\n                    .alert--license .alert__body{\n                        flex: 1;\n                        margin-right: auto;\n                    }\n                    .alert--license b{\n                        font-size: 14px;\n                        display: block;\n                        margin-bottom: 8px;\n                    }\n                    .alert--license b .hidden{\n                        display: inline-block!important;\n                    }\n                    .alert--license p{\n                        color: #505459;\n                        margin-bottom: 0;\n                    }\n                    .alert--license .alert__actions{\n                        display: flex;\n                        flex: 0 1 auto;\n                        white-space: nowrap;\n                    }\n                    .alert--license .alert__actions>*+* {\n                        margin-left: 16px;\n                    }\n                    .alert--license .alert__actions:last-child{\n                        margin-left: 16px;\n                    }\n                    .alert--license:after{\n                        position: absolute;\n                        top: -1px;\n                        bottom: -1px;\n                        left: -1px;\n                        content: \"\";\n                        border-radius: 3px 0 0 3px;\n                        border-left: 4px solid;\n                    }\n                    .widget-settings{\n                        margin-top: -28px;\n                    }\n                    .alert--license .form-checkbox + .form-indicator {\n                        position: relative;\n                        width: 22px;\n                        height: 22px;\n                        min-width: 22px;\n                        border-radius: 3px;\n                        display: inline-flex;\n                        align-items: center;\n                        justify-content: center;\n                        color: #393D45;\n                        border: 1px solid #d7d9de;\n                        background-color: #ffffff;\n                        box-shadow: none;\n                    }\n                    .alert--license .form-checkbox{\n                        display: none;\n                    }\n                    .alert--license .form-check label{\n                        display: flex;\n                        align-items: center;\n                        font-weight: 400;\n                        color: #505459;\n                    }\n                    .alert--license .form-text{\n                        margin-left: 8px;\n                    } \n                    \n                    .alert--license .form-checkbox + .form-indicator:hover,\n                    .alert--license .form-checkbox + .form-indicator:active{\n                        border-color: #1062FE;\n                        outline: 0;\n                    }\n                    .alert--license .form-checkbox:checked + .form-indicator{\n                        background: #50bfff;\n                        border-color: #50bfff;\n                    }\n                    .alert--license .form-checkbox:checked + .form-indicator:before{\n                        position: absolute;\n                        top: 0;\n                        left: 0;\n                        right: 0;\n                        bottom: 0;\n                        display: inline-flex;\n                        align-items: center;\n                        justify-content: center;\n                        font-family: Material-Design-Iconic-Font;\n                        content: \"\\f26b\";\n                        display: inline-flex;\n                        color: #fff;\n                    }\n                    .alert--license .m-t-1x{\n                        margin-top: 8px;\n                    }\n                </style>\n                <script>\n                 \$(\".alert--license\").on(\"closed.bs.alert\", function () {\n                    let notshow = \$(this).find(\"[data-dont-show]\");\n                    let name = \"licenseexp\",\n                        value = 1,\n                        days = 7;\n            \n                    if (notshow[0].checked === true){\n                        value = \"4ever\";\n                        days = 9999;\n                    }\n\n                    new setCookie(name, value, days);\n                    \n                 });\n\n                 function setCookie(cname, cvalue, exdays) {\n                    const d = new Date();\n                    d.setTime(d.getTime() + (exdays*24*60*60*1000));\n                    let expires = \"expires=\"+ d.toUTCString();\n                    document.cookie = cname + \"=\" + cvalue + \";\" + expires + \";path=/\";\n                  }\n                </script>";
                }
            }
            if (isset($this->licenseDetails["warningShowDate"]) && strlen($this->licenseDetails["warningShowDate"]) && $this->licenseDetails["warningShowDate"] <= date("Y-m-d")) {
                $days = \Carbon\Carbon::today()->diffInDays(\Carbon\Carbon::parse($this->licenseDetails["deactivationDate"]), false);
                if ($days < $this->licenseFailDays) {
                    $html .= "<div class=\"alert alert--outline has-icon alert--border-left alert--license alert--danger\"><div class=\"alert__body\">";
                    $html .= str_replace("%days%", $days, \RSThemes\Helpers\Messages::get("warnings.9"));
                    $html = str_replace("<b>ERROR:", "<b>ERROR: Lagom WHMCS Client Theme", $html);
                    $html .= "</div><div class=\"alert__actions\">\n                            <a class=\"btn btn-default\" href=\"#\" target=\"_blank\">Support</a>\n                            </div>";
                    $html .= "</div>";
                    $html .= "<style>\n                    @font-face {\n                        font-family: \"Material-Design-Iconic-Font\";\n                        src: url(\"https://cdnjs.cloudflare.com/ajax/libs/material-design-iconic-font/2.2.0//fonts/Material-Design-Iconic-Font.woff2?v=2.2.0\") format(\"woff2\"), url(\"https://cdnjs.cloudflare.com/ajax/libs/material-design-iconic-font/2.2.0//fonts/Material-Design-Iconic-Font.woff?v=2.2.0\") format(\"woff\"), url(\"https://cdnjs.cloudflare.com/ajax/libs/material-design-iconic-font/2.2.0//fonts/Material-Design-Iconic-Font.ttf?v=2.2.0\") format(\"truetype\");\n                        font-weight: normal;\n                        font-style: normal;\n                    }\n                    .alert--license{\n                        position: relative;\n                        display: flex;\n                        justify-content: space-between;\n                        align-items: center;\n                        flex-flow: row wrap;\n                        padding: 13px 16px 13px 56px;\n                       \n                        margin-bottom: 32px;\n                        border: none;\n                        box-shadow: 0 2px 8px rgba(0,0,0,0.08);\n                        background: #fff;\n                        \n                    }\n                    .alert--license.alert--danger{\n                        color: #e53e3e;\n                        border-color: #e53e3e;\n                    }\n                    .alert--license *{\n                        box-sizing: border-box;\n                    }\n                    .alert--license:before{\n                        position: absolute;\n                        top: 50%;\n                        left: 15px;\n                        width: 24px;\n                        height: 24px;\n                        margin-top: -12px;\n                        text-align: center;\n                        font-family: Material-Design-Iconic-Font;\n                        font-size: 24px;\n                        line-height: 22px;\n                    }\n                    .alert--license.alert--danger:before{\n                        content: \"\\f1f4\";\n                    }\n                    .alert--license .alert__body{\n                        flex: 1;\n                        margin-right: auto;\n                    }\n                    .alert--license b{\n                        font-size: 14px;\n                        display: block;\n                        margin-bottom: 8px;\n                    }\n                    .alert--license b .hidden{\n                        display: inline-block!important;\n                    }\n                    .alert--license p{\n                        color: #505459;\n                        margin-bottom: 0;\n                    }\n                    .alert--license .alert__actions{\n                        display: flex;\n                        flex: 0 1 auto;\n                        white-space: nowrap;\n                    }\n                    .alert--license .alert__actions>*+* {\n                        margin-left: 16px;\n                    }\n                    .alert--license .alert__actions:last-child{\n                        margin-left: 16px;\n                    }\n                    .alert--license:after{\n                        position: absolute;\n                        top: -1px;\n                        bottom: -1px;\n                        left: -1px;\n                        content: \"\";\n                        border-radius: 3px 0 0 3px;\n                        border-left: 4px solid;\n                    }\n                    .widget-settings{\n                        margin-top: -28px;\n                    }\n                </style>";
                }
            }
            return $html;
        }
        public function hasProblem()
        {
            if (isset($this->licenseDetails["warningShowDate"]) && strlen($this->licenseDetails["warningShowDate"]) && $this->licenseDetails["warningShowDate"] <= date("Y-m-d")) {
                return true;
            }
            return false;
        }
        public function getProblem()
        {
            if (isset($this->licenseDetails["warningShowDate"]) && strlen($this->licenseDetails["warningShowDate"]) && $this->licenseDetails["warningShowDate"] <= date("Y-m-d")) {
                return $this->getMessagePart("warnings.8", 0);
            }
            return "";
        }
        public function hasInputError()
        {
            if (strlen($this->licenseKey) <= 0 || $this->licenseDetails["license_status"] == "") {
                return true;
            }
            return false;
        }
        public function getInputError()
        {
            if (strlen($this->licenseKey) <= 0 || $this->licenseDetails["license_status"] == "") {
                return \RSThemes\Helpers\Messages::get("messages.1");
            }
        }
        public function getAddonMessages()
        {
            $html = "";
            if (0 < strlen($this->licenseDetails["nextduedate"]) && $this->licenseDetails["nextduedate"] != "0000-00-00") {
                $dueDateDiff = \Carbon\Carbon::today()->diffInDays(\Carbon\Carbon::parse($this->licenseDetails["nextduedate"]), false);
                $notShow = false;
                if (isset($_COOKIE["licenseexp"]) && ($_COOKIE["licenseexp"] == "4ever" || $_COOKIE["licenseexp"] == "1" && 2 < $dueDateDiff)) {
                    $notShow = true;
                }
                if (0 <= $dueDateDiff && $dueDateDiff <= 30 && !$notShow) {
                    $html .= "<div class=\"alert alert--info alert--outline has-icon alert--border-left alert--license\" data-daysToExp=\"" . $dueDateDiff . "\"><div class=\"alert__body\">";
                    if ($dueDateDiff == 0) {
                        $html .= str_replace("%days%", $dueDateDiff, \RSThemes\Helpers\Messages::get("warnings.6"));
                    } else {
                        $html .= str_replace("%days%", $dueDateDiff, \RSThemes\Helpers\Messages::get("warnings.5"));
                    }
                    $html .= "<div class=\"form-check\"><label class=\"m-b-0x m-t-1x\"><input type=\"checkbox\" name=\"notshow\" data-dont-show class=\"form-checkbox\"><span class=\"form-indicator\"></span><span class=\"form-text\">Do not show again</span></label></div>";
                    $html .= "</div><div class=\"alert__actions\">\n                            <a class=\"btn btn--default btn--outline btn--sm\" href=\"https://rsstudio.net/my-account/\" target=\"_blank\">Pay Now</a>\n                            <button class=\"btn btn--default btn--outline btn--sm\" data-dismiss=\"alert\" aria-label=\"Close\" type=\"button\">Dismiss</button>\n                        </div>";
                    $html .= "</div>";
                }
            }
            if (isset($this->licenseDetails["warningShowDate"]) && strlen($this->licenseDetails["warningShowDate"]) && $this->licenseDetails["warningShowDate"] <= date("Y-m-d")) {
                $days = \Carbon\Carbon::today()->diffInDays(\Carbon\Carbon::parse($this->licenseDetails["deactivationDate"]), false);
                $html .= "<div class=\"alert alert--danger alert--outline has-icon alert--border-left alert--license\"><div class=\"alert__body\">";
                $html .= str_replace("%days%", $days, \RSThemes\Helpers\Messages::get("warnings.9"));
                $html .= "</div><div class=\"alert__actions\">\n                <a class=\"btn btn--default btn--outline btn--sm\" href=\"https://rsstudio.net/my-account/submitticket.php?step=2&deptid=7\" target=\"_blank\">Contact Us</a>\n                </div>";
                $html .= "</div>";
            }
            if (0 < strlen($this->licenseWarningMessage)) {
                $html .= "<div class=\"alert alert--danger alert--outline has-icon alert--border-left alert--license\"><div class=\"alert__body\">";
                $html .= $this->licenseWarningMessage;
                $html .= "</div><div class=\"alert__actions\">\n                <a class=\"btn btn--default btn--outline btn--sm\" href=\"https://rsstudio.net/my-account/submitticket.php?step=2&deptid=7\" target=\"_blank\">Contact Us</a>\n                </div>";
                $html .= "</div>";
            }
            return $html;
        }
        private static function checkLogFile()
        {
            $path = RSTHEMES_DIR . DS . "logs.php";
            if (!is_writable(RSTHEMES_DIR)) {
                return false;
            }
            if (!file_exists($path)) {
                try {
                    file_put_contents($path, "<?php http_response_code(404);exit; ?>\\nCreate logs file! " . date("Y-m-d h:i:s") . PHP_EOL);
                    if (!file_exists($path)) {
                        return false;
                    }
                } catch (\Exception $exception) {
                    return false;
                }
            }
            if (!is_writable($path)) {
                return false;
            }
            return $path;
        }
        public function getAllowedExtensions()
        {
            if ($this->licenseDetails["service_status"] == "Active") {
                $details = $this->reloadRemote();
            }
            return $details["extensions"] ? explode(",", trim($details["extensions"])) : [];
        }
        private function syncExtensions($details)
        {
            $toSkip = ["Modules Integrations"];
            if ($details["license_status"] != "Active") {
                return NULL;
            }
            $allowedExtensions = $details["extensions"] ? explode(",", trim($details["extensions"])) : [];
            foreach ($this->template->getExtensions() as $extension) {
                if (!in_array($extension->name, $toSkip)) {
                    if (method_exists($extension, "checkLicense") && !in_array($extension->name, $allowedExtensions) && $extension->isActive()) {
                        $extension->licenseRemoveConfig();
                    }
                }
            }
        }
    }
    
    ?>

  • Lagom Website Builder By RSStudio 1.0.3 破解版开心版

    2024年07月30日更新:已完美破解。

    Lagom WHMCS Website Builder V1.0.3 Nulled

    • 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.
    • FIX Other minor appearance fixes.
  • Lagom WHMCS Client Theme By RSStudio 2.2.6 破解版开心版

    Lagom WHMCS Client Theme By RSStudio v2.2.6 Nulled

    Client Area​

    • NEW Header Collapse – A new submenu element type, that enables creating collapsible groups in the Main Menu – Case #889.
    • NEW WHMCS SiteJet Builder is now supported with correctly displayed information on the Product Details page – Case #879.
    • NEW Hide Billing Cycle Discounts – New feature allowing to simplify pricing displays by removing discount calculations related to different billing cycles – Case #916.
    • Improvements Removed unnecessary pagination and added the display of an alert for a Critical report on the Network Status page – Case #741.
    • Improvements Updated the display of the product quantity label for the “View Cart” element in the menu – Case #766.
    • FIX Fixed an issue when the SVG icons had improper colors when used in submenu element of the Left Wide menu layout – Case #876.
    • FIX Fixed an issue where long UTF-8 text inputs were not accepted in the “Description” field of the “Mega Menu” sub-menu style – Case #873.
    • FIX Other minor appearance fixes.

    Order Process​

    • FIX Fixed a display issue with currency formatting (1,234) and removed the “/mo” suffix when the Monthly Breakdown option is disabled – Case #875.
    • FIX Fixed an issue that prevented product upgrades when higher-tier product packages were set to “Stock Control” at zero – Case #865.
    • FIX Fixed the price calculation and display on the View Cart page for Configurable Options when changing product’s billing cycle – Case #877.
    • FIX Other minor appearance fixes.
  • Lagom Website Builder By RSStudio V1.0.2 Nulled 开心版破解版

    Lagom Website Builder自发布以来终于迎来了一次大的更新。

    通过 Lagom Website Builder你可以任意改变你的主机网站的格局,有非常多的构建器可以选择,让你的主机网站与其它的有明显的不同。

    Lagom WHMCS 主题的强大网站构建器 使用 Lagom WHMCS 网站构建器提升您的在线形象。
    创建一个给人留下持久印象并与您的受众产生共鸣的网站。


    一键式网站设置


    Lagom WHMCS 网站构建器拥有 40 多个预先设计页面的多功能库,可满足各种产品类型和网站要求。快速轻松地自定义它们以满足您的特定需求。

    网站页面管理


    使用 Lagom WHMCS 网站构建器体验轻松的页面管理并解锁自定义可能性的世界。以前所未有的方式控制您的网站。

    网站网站地图构建器


    使用 Lagom WHMCS 网站构建器轻松创建站点地图。每当您添加新页面时,站点地图都会自动生成,从而简化流程并确保您的网站保持 SEO 友好。

    多种版块类型


    在 Lagom WHMCS 网站构建器中,您会发现丰富的预设计版块类型选择,让您只需单击几下即可轻松创建独特且量身定制的网站页面。

    破解方法

    1,安装 lagom 2.2.5 破解版.

    [b2_insert_post id=”7488″]

    2,安装本插件破解版。