Jump to content

Basic Licensing addon tutorial - for those who need a little extra help


bigideaguy

Recommended Posts

I just bought this addon today and so far it seems great but I wish WHMCS would have helped me a little more setting it up. I saw lots of others with the same questions but no one seemed to have an easy solution. So I played around with it and learned it on my own and I have tried to explain it as best as I can on my blog.

 

I did not reveal any code of the addon, you will need to buy it to understand the tutorial.

 

To WHMCS: If you want me to remove the tutorial I will promptly and happily do so, however I tried to make it useful to license owners without giving anything away to lurkers.

 

Here is the link:

 

http://markspixel.com/2010/09/01/how-to-configure-and-setup-whmcs-licensing-addon/

Link to comment
Share on other sites

  • 3 weeks later...

You would add the licensing code to your current php script, any code that is only in the "active" section of the licensing script will only display for an active license. It should be fairly simple to do, did you take a look at the tutorial I wrote above? If you need anymore help don't hesitate to contact me via the markspixel.com contact form.

Link to comment
Share on other sites

i got it for the most part i just need help cus it still lets the script run

 

i am useing two files for it and i have included them

 

include("key.php"); < key file where the key is at

include("lil.php"); < where the whmcs lis script it

 

my php script calls that file

Link to comment
Share on other sites

HI bigideaguy

 

i have fallow you tutorial and it works but

if i use the same license key in anther script it works

so if the client get 2 script he cane use one license key for the 2 script

 

My question

 

How do i get the license key work on one script in the same website?

Without having access to the modules source, I believe the only way to do this at present would be to modify the license check function to utilize one of the restricted variables (i.e. installation folder) to be a constant; for example, you could have application #1 report the directory as "app_1", application #2 report it as "app_2", and so on. Then in the products module settings area, ensure that "Allow Directory Conflict" is unchecked. Not a perfect way of handling this, but should do what you want though.

 

With that said, I see that since replacing one of the license modules files, as obtained from Matt, there is a new field there that wasn't before; the "Secret Key" field. If handled correctly, this could be used for the exact purpose of issuing separate licenses for multiple products and not allowing them to be used between each other. I had meant to submit a ticket asking Matt exactly how this new field is implemented within the module and what can be done with it, but haven't ahd time yet to do so; I'll do that after I post this. Besides the basic MD5 stuff, it could very well be used to limit a license to a certain product by making each products secret key unique; provided that it's implemented the right way within the licensing system.

Edited by GGWH-James
Link to comment
Share on other sites

Without having access to the modules source, I believe the only way to do this at present would be to modify the license check function to utilize one of the restricted variables (i.e. installation folder) to be a constant; for example, you could have application #1 report the directory as "app_1", application #2 report it as "app_2", and so on. Then in the products module settings area, ensure that "Allow Directory Conflict" is unchecked. Not a perfect way of handling this, but should do what you want though.

 

With that said, I see that since replacing one of the license modules files, as obtained from Matt, there is a new field there that wasn't before; the "Secret Key" field. If handled correctly, this could be used for the exact purpose of issuing separate licenses for multiple products and not allowing them to be used between each other. I had meant to submit a ticket asking Matt exactly how this new field is implemented within the module and what can be done with it, but haven't ahd time yet to do so; I'll do that after I post this. Besides the basic MD5 stuff, it could very well be used to limit a license to a certain product by making each products secret key unique; provided that it's implemented the right way within the licensing system.

 

Yes, interesting stuff. I will also try to ponder on this issue, but like you said, with the source encrypted it would be tough.

Link to comment
Share on other sites

Yes, interesting stuff. I will also try to ponder on this issue, but like you said, with the source encrypted it would be tough.

Thinking about this, why over-complicate it. There is already the option to specify a key prefix with each product. Quite simply, use a distinct prefix for each product and put code into your application to cehck the license entered and verify if it starts with that prefix or not prior to even validating it with the licensing server.

Link to comment
Share on other sites

Thinking about this, why over-complicate it. There is already the option to specify a key prefix with each product. Quite simply, use a distinct prefix for each product and put code into your application to cehck the license entered and verify if it starts with that prefix or not prior to even validating it with the licensing server.

Something like below could be added to the top of the check_license function:

 

if (!preg_match("/^(Leased-)/", $licensekey))
{
// Input license does not start with "Leased-", invalidate it.
$licensekey = "Invalid-" . mt_rand(1,  mt_getrandmax());
}

 

There are other ways to do it which would involve not even performing the license check if the code is recognized as an invalid format and forcing it's re-entry, but the above is the simplest to understand and implement.

Edited by GGWH-James
Link to comment
Share on other sites

Something like below could be added to the top of the check_license function:

 

if (!preg_match("/^(Leased-)/", $licensekey))
{
// Input license does not start with "Leased-", invalidate it.
$licensekey = "Invalid-" . mt_rand(1,  mt_getrandmax());
}

 

There are other ways to do it which would involve not even performing the license check if the code is recognized as an invalid format and forcing it's re-entry, but the above is the simplest to understand and implement.

If you have multiple license types for one product:

 

 if (!preg_match("/^(Leased-|Owned-)/", $licensekey))
{
 // Input license does not start with "Leased-" or "Owned-", invalidate it.
 $licensekey = "Invalid-" . mt_rand(1,  mt_getrandmax());
}

Edited by GGWH-James
Link to comment
Share on other sites

Below is something I ahve been testing today:

 

 if (!preg_match("/^(Leased-|Owned-)/", $licensekey))
{
 // Input license does not start with "Leased-" or "Owned-", invalidate it.
 $licensekey = "Invalid-" . $licensekey;
}

 

This not only invalidates the key, but allows you to see in the unauthorized log of your licensing module who is attempting to use a key with a wrong product. Since the key they input is contained within the log, simply strip "Invalid-", you can match that up with the client who owns the key if you like. You would never create a product with a key prefix of "Invalid-" for what should be obvious reasons.

Edited by GGWH-James
Link to comment
Share on other sites

Hi Jamroar

 

here is an update for my test and it works perfect

 

add

 


$product_name = $results["productname"];

if ($product_name == "PRODUCT NAME") {    #change PRODUCT NAME to your product name 


at the top of

 


if ($results["status"]=="Active") {
   # Allow Script to Run

and in the end of the cod add


}  else{

echo 'Invalid';
}


at the top of

?>

i am working on how to Verify the domain so it will be working on one domain only so cane you help me withe this

Edited by HardSoftCode
Link to comment
Share on other sites

I found it easier to validate against the "productid" instead though.

 

I put the following code below "// End Check Function":

if (!in_array($results["productid"], array(66, 99)))
{
$results["status"] = "Product";
}

 

You then can add the following after the Suspended elseif:

 

elseif ($results["status"] == "Product")
{
# Show Wrong Product Message
// die("The license entered is for " . htmlentities($results['productname'], ENT_QUOTES) . " not for Your_Product_Name_Here";
}

 

You can do whatever you want with that new status. I just provided an example. As for the domain thing, that's a feature that can be set within the module settings for the product.

Edited by GGWH-James
Link to comment
Share on other sites

Hi Jamroar

 

i did find the way to Verify the domain and the directory and the Ip

 

here is what i got

 


$valid_domain = $_SERVER["HTTP_HOST"];
$valid_directory = dirname(__FILE__);
$valid_ip = $_SERVER['SERVER_ADDR'];

if ($valid_domain = $results["validdomain"]) {
if ($valid_ip == $results["validip"]) {
if ($valid_directory == $results["validdirectory"]) {

if ($results["status"]=="Active") {
   # Allow Script to Run

 

in the end add


}  
else{

echo 'Invalid Directory';
}
}  else{

echo 'Invalid IP';
} 
}  else{

echo 'Invalid Domain';
}
?>

 

i don't need to Verify the product name any moor as i have Verify the domain and the directory of the product

Link to comment
Share on other sites

  • 1 year later...

Okay maybe i'm not getting this right. well it's apparent that i'm not getting this right.

 

Can someone please help me.

 

Here's the website i'm putting this on.

 

ltest_error.jpg

 

This is the code i'm using for the copy and paste.php file

<?php

// Begin Check Function
include("addwire.php"); #License File for Client to input the License.

function check_license($licensekey,$localkey="") {
   $whmcsurl = "http://www.addwire.com/manage/";
   $licensing_secret_key = "oscommerce01"; # Unique value, should match what is set in the product configuration for MD5 Hash Verification
   $check_token = time().md5(mt_rand(1000000000,9999999999).$licensekey);
   $checkdate = date("Ymd"); # Current date
   $usersip = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : $_SERVER['LOCAL_ADDR'];
   $localkeydays = 15; # How long the local key is valid for in between remote checks
   $allowcheckfaildays = 5; # How many days to allow after local key expiry before blocking access if connection cannot be made
   $localkeyvalid = false;
   if ($localkey) {
       $localkey = str_replace("\n",'',$localkey); # Remove the line breaks
	$localdata = substr($localkey,0,strlen($localkey)-32); # Extract License Data
	$md5hash = substr($localkey,strlen($localkey)-32); # Extract MD5 Hash
       if ($md5hash==md5($localdata.$licensing_secret_key)) {
           $localdata = strrev($localdata); # Reverse the string
   		$md5hash = substr($localdata,0,32); # Extract MD5 Hash
   		$localdata = substr($localdata,32); # Extract License Data
   		$localdata = base64_decode($localdata);
   		$localkeyresults = unserialize($localdata);
           $originalcheckdate = $localkeyresults["checkdate"];
           if ($md5hash==md5($originalcheckdate.$licensing_secret_key)) {
               $localexpiry = date("Ymd",mktime(0,0,0,date("m"),date("d")-$localkeydays,date("Y")));
               if ($originalcheckdate>$localexpiry) {
                   $localkeyvalid = true;
                   $results = $localkeyresults;
                   $validdomains = explode(",",$results["validdomain"]);
                   if (!in_array($_SERVER['SERVER_NAME'], $validdomains)) {
                       $localkeyvalid = false;
                       $localkeyresults["status"] = "Invalid";
                       $results = array();
                   }
                   $validips = explode(",",$results["validip"]);
                   if (!in_array($usersip, $validips)) {
                       $localkeyvalid = false;
                       $localkeyresults["status"] = "Invalid";
                       $results = array();
                   }
                   if ($results["validdirectory"]!=dirname(__FILE__)) {
                       $localkeyvalid = false;
                       $localkeyresults["status"] = "Invalid";
                       $results = array();
                   }
               }
           }
       }
   }
   if (!$localkeyvalid) {
       $postfields["licensekey"] = $licensekey;
       $postfields["domain"] = $_SERVER['SERVER_NAME'];
       $postfields["ip"] = $usersip;
       $postfields["dir"] = dirname(__FILE__);
       if ($check_token) $postfields["check_token"] = $check_token;
       if (function_exists("curl_exec")) {
           $ch = curl_init();
           curl_setopt($ch, CURLOPT_URL, $whmcsurl."modules/servers/licensing/verify.php");
           curl_setopt($ch, CURLOPT_POST, 1);
           curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields);
           curl_setopt($ch, CURLOPT_TIMEOUT, 30);
           curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
           $data = curl_exec($ch);
           curl_close($ch);
       } else {
           $fp = fsockopen($whmcsurl, 80, $errno, $errstr, 5);
        if ($fp) {
       		$querystring = "";
               foreach ($postfields AS $k=>$v) {
                   $querystring .= "$k=".urlencode($v)."&";
               }
               $header="POST ".$whmcsurl."modules/servers/licensing/verify.php HTTP/1.0\r\n";
       		$header.="Host: ".$whmcsurl."\r\n";
       		$header.="Content-type: application/x-www-form-urlencoded\r\n";
       		$header.="Content-length: ".@strlen($querystring)."\r\n";
       		$header.="Connection: close\r\n\r\n";
       		$header.=$querystring;
       		$data="";
       		@stream_set_timeout($fp, 20);
       		@fputs($fp, $header);
       		$status = @socket_get_status($fp);
       		while (!@feof($fp)&&$status) {
       		    $data .= @fgets($fp, 1024);
       			$status = @socket_get_status($fp);
       		}
       		@fclose ($fp);
           }
       }
       if (!$data) {
           $localexpiry = date("Ymd",mktime(0,0,0,date("m"),date("d")-($localkeydays+$allowcheckfaildays),date("Y")));
           if ($originalcheckdate>$localexpiry) {
               $results = $localkeyresults;
           } else {
               $results["status"] = "Invalid";
               $results["description"] = "Remote Check Failed";
               return $results;
           }
       } else {
           preg_match_all('/<(.*?)>([^<]+)<\/\\1>/i', $data, $matches);
           $results = array();
           foreach ($matches[1] AS $k=>$v) {
               $results[$v] = $matches[2][$k];
           }
       }
       if ($results["md5hash"]) {
           if ($results["md5hash"]!=md5($licensing_secret_key.$check_token)) {
               $results["status"] = "Invalid";
               $results["description"] = "MD5 Checksum Verification Failed";
               return $results;
           }
       }
       if ($results["status"]=="Active") {
           $results["checkdate"] = $checkdate;
           $data_encoded = serialize($results);
           $data_encoded = base64_encode($data_encoded);
           $data_encoded = md5($checkdate.$licensing_secret_key).$data_encoded;
           $data_encoded = strrev($data_encoded);
           $data_encoded = $data_encoded.md5($data_encoded.$licensing_secret_key);
           $data_encoded = wordwrap($data_encoded,80,"\n",true);
           $results["localkey"] = $data_encoded;
       }
       $results["remotecheck"] = true;
   }
   unset($postfields,$data,$matches,$whmcsurl,$licensing_secret_key,$checkdate,$usersip,$localkeydays,$allowcheckfaildays,$md5hash);
   return $results;
}

// End Check Function

# Get Variables from storage (retrieve from wherever it's stored - DB, file, etc...)
$licensekey = "$license_key";
$localkey = '9tjIxIzNwgDMwIjI6gjOztjIlRXYkt2Ylh2YioTO6M3OicmbpNnblNWasx1cyVmdyV2ccNXZsVHZv1GX
zNWbodHXlNmc192czNWbodHXzN2bkRHacBFUNFEWcNHduVWb1N2bExFd0FWTcNnclNXVcpzQioDM4ozc
7ISey9GdjVmcpRGZpxWY2JiO0EjOztjIx4CMuAjL3ITMioTO6M3OiAXaklGbhZnI6cjOztjI0N3boxWY
j9Gbuc3d3xCdz9GasF2YvxmI6MjM6M3Oi4Wah12bkRWasFmdioTMxozc7ISeshGdu9WTiozN6M3OiUGb
jl3Yn5WasxWaiJiOyEjOztjI3ATL4ATL4ADMyIiOwEjOztjIlRXYkVWdkRHel5mI6ETM6M3OicDMtcDM
tgDMwIjI6ATM6M3OiUGdhR2ZlJnI6cjOztjIlNXYlxEI5xGa052bNByUD1ESXJiO5EjOztjIl1WYuR3Y
1R2byBnI6ETM6M3OicjI6EjOztjIklGdjVHZvJHcioTO6M3Oi02bj5ycj1Ga3BEd0FWbioDNxozc7ICb
pFWblJiO1ozc7IyUD1ESXBCd0FWTioDMxozc7ISZtFmbkVmclR3cpdWZyJiO0EjOztjIlZXa0NWQiojN
6M3OiMXd0FGdzJiO2ozc7pjMxoTY8baca0885830a33725148e94e693f3f073294c0558d38e31f844
c5e399e3c16a';

# The call below actually performs the license check. You need to pass in the license key and the local key data
$results = check_license($licensekey,$localkey);

# For Debugging, Echo Results
echo "<textarea cols=100 rows=20>"; print_r($results); echo "</textarea>";

$product_name = $results["productname"];

if ($product_name == "Unlimited osCommerce Templates") {    #change PRODUCT NAME to your product name  
if ($results["status"]=="Active") {
   # Allow Script to Run
   if ($results["localkey"]) {
       # Save Updated Local Key to DB or File
       $localkeydata = $results["localkey"];
   }
include("index.html");
} elseif ($results["status"]=="Invalid") {
   # Show Invalid Message
} elseif ($results["status"]=="Expired") {
   # Show Expired Message
} elseif ($results["status"]=="Suspended") {
   # Show Suspended Message
}
}  else{

echo 'Oops Something went wrong with your license. Please contact +ADDWiRE Network Support at support@addwire.com';
} 

?>

 

Here is the License info on WHMCS:

 

client_admin.jpg

 

 

What am i doing wrong? I see the Hash isnt correct, if thats the problem, well how do i fix it?

Link to comment
Share on other sites

  • 5 months later...

What do you mean by make this work?

 

The local key is the thing that stops the license checking code having to call your server on every page load. It's basically just an encrypted version of the license check data, so that when it's present and valid, the licensing addon doesn't have to make a remote call which would slow down your application/code, thus improving performance. The local key will always be empty on the first check your client makes, but then with every successful remote check, a local key value is returned (sample code provided) which you then just need to store and pass into any future license check calls. We recommend storing into a database for ease of updating and retrieval, but flat files can work just as well.

 

I will look into it a bit more since I never really needed to use it for anything i do. I will post back here when I have an update.

Link to comment
Share on other sites

Ok so this helped. Knowing that the localkey is generated the first time you run the script. I then store it in the database. But now my question is, do I need to call the local key from the db each time and assign it to $localkey so that in 15 days it works again? Or do I not need to do anything and it'll just keep generating the same localkey based on the license key?

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use & Guidelines and understand your posts will initially be pre-moderated