Loading...

Storefront-Based Add-on Licensing in Ultimate Edition

We no longer maintain the Knowledge Base since version 4.3.x. All the latest user and developer documentation for 4.3.x and newer versions is now available at docs.cs-cart.com.

  • This article applies to CS-Cart versions:
  • 3.0.x

This tutorial covers the specific topic of separate add-on licensing for storefronts in CS-Cart Ultimate edition.

If you want to learn add-on licensing in CS-Cart Professional, Multi-Vendor, or storefront-independent add-on licensing in CS-Cart Ultimate, proceed to the general Add-on Licensing tutorial.

Due to architecture issues, it is impossible to set add-on statuse specifically for a particular storefront. So even if an add-on is not licensed for a particular storefront, it will anyway appear on the 'Add-Ons' page with the same status as for the root administrator. The storefront administrator will not be able to use the add-on though.

Add-on Initialization: addon.xml, init.php

In the directory addons within your store installation root directory create the add-on folder, e.g. licensed_addon_multi.

Create the file addon.xml to contain the add-on information and several licensing settings (download):

addons/licensed_addon_multi/addon.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?xml version="1.0"?>
<addon scheme="2.0">
    <id>license_addon</id>
    <name>License Addon</name>
    <priority>100500</priority>
    <position>0</position>
    <status>active</status>
 
    <settings edition_type="ULT:VENDOR">
        <sections>
            <section id="main">
                <items>
                    <item id="license_number"> 
                        <name>License number</name> <!-- License number. This field will be available for editing in the add-on settings -->
                        <type>input</type>
                    </item>
                    <item id="license_server">
                        <name>License Server</name> <!-- License validation URL. This is a hidden field not available for editing, so its value is set right here -->
                        <type>hidden</type>
                        <default_value>localhost/valid.php</default_value>
                    </item>
                    <item id="license_valid">
                        <name>License valid</name> <!-- This setting will hold the validation result ('true' or 'false'). Updated after every license check -->
                        <type>hidden</type>
                    </item>
                </items>
            </section>
        </sections>
    </settings>
    <language_variables>
        <!-- Language variable for the invalid license notification -->
        <item lang="EN" id="addon_license_invalid">Add-on license is not valid</item>
    </language_variables>
</addon>

The file init.php will prevent the add-on from executing. It should have the following content (download):

addons/licensed_addon_multi/init.php
1
2
3
4
5
<?php
 
if ( !defined('AREA') ) { die('Access denied'); }
 
?>

Add-on Management: func.php

The file func.php in the add-on folder will contain some add-on management functions (download):

addons/licensed_addon_multi/func.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
<?php
 
if ( !defined('AREA') ) { die('Access denied'); }
 
// Sending license data to the validation server
function fn_license_addon_get_license_information()
{
 
    // Collecting all available add-on licenses
 
    // For storefront-based licensing it is necessary to build licenses for every storefront
    $storefronts = array();
 
    // Obtain all active storefronts
    list($all_storefronts) = fn_get_companies(array(), $_SESSION['auth']);
 
    if (!empty($all_storefronts)) {
        foreach($all_storefronts as $store) {
            if (!empty($store['storefront'])) {
                // Get licenses for storefronts
                $license_number = CSettings::instance()->get_value('license_number', 'license_addon', $store['company_id']);
 
                // Pack the data in a handy array
                $storefronts[$store['company_id']] = array(
                    'store_uri' => $store['storefront'],
                    'license_number' => (!empty($license_number) ? $license_number : ''),
                );
            }
        }
    }
 
 
    if (!empty($storefronts)) {
    // If no licenses are available, nothing needs to be sent
 
        $store_ip = fn_get_ip();
        $store_ip = $store_ip['host'];
 
        // Preparing the store data for sending to the server
        $request = array(
            'ver' => PRODUCT_VERSION,
            'product_status' => PRODUCT_STATUS,
            'product_build' => PRODUCT_BUILD,
            'edition' => PRODUCT_TYPE,
            'store_ip' => $store_ip,
            'storefronts' => $storefronts,
        );
 
        // Sending the data in the JSON format to the server over a secure HTTPS channel
        list($header, $data) = fn_http_request('POST', Registry::get('addons.license_addon.license_server'), array('data' => json_encode($request)));
 
    } else {
        // If nothing was sent, returning false
        $data = false;
    }
 
    // Examples of the server response
    // '{"storefronts_status":{"1":"true","2":"false"}}'
 
    return $data;
}
 
// The function parses the server response and deactivates the add-on if necessary
function fn_license_addon_parse_license_information($data)
{
    $data = json_decode($data, true);
 
    list($storefronts) = fn_get_companies(array(), $_SESSION['auth']);
    if (!empty($storefronts)) {
        foreach($storefronts as $id => $store) {
            // Assigning the statuses received from the server. In case of missing status data for a particular storefront status 'false' is assigned
            fn_license_addon_change_status_addon(!empty($data['storefronts_status'][$store['company_id']]) ? $data['storefronts_status'][$store['company_id']] : 'false', $store['company_id']);
        }
    }
 
    return true;
}
 
// Add-on validity check
function fn_license_addon_check_valid()
{
    // Getting add-on status
    $result = Registry::get('addons.license_addon.license_valid');
 
    if (defined('SELECTED_COMPANY_ID') && SELECTED_COMPANY_ID == 'all') {
        // If no storefront is selected, the add-on is considered valid
        $result = true;
    }
 
    return !empty($result) && $result !== 'false' ? true : false;
}
 
// Changing add-on status for a particular storefront
function fn_license_addon_change_status_addon($status, $company_id = 0)
{
    // Changing add-on status for the specified storefront
    CSettings::instance()->update_value('license_valid', (!empty($status) && $status !== 'false' ? 'true' : 'false'), 'license_addon', true, (!empty($company_id) ? $company_id : (defined('COMPANY_ID') ? COMPANY_ID : null)));
}
 
?>

Add-on license check

The add-on license will be validated on 3 events:

  • after admin panel authorization
  • on add-on status change
  • on license number change

Post-Authorization Check

Within the add-on directory (addons/licensed_addon) create the subfolders controllers/admin and place he file auth.post.php in it. It is a postcontroller for the auth.php controller and will contain a simple license validation routine (download):

addons/licensed_addon_multi/controllers/admin/auth.post.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
 
if ( !defined('AREA') ) { die('Access denied'); }
 
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
 
    if ($mode == 'login') {
 
        // Requesting license data from the server
        $data = fn_license_addon_get_license_information();
 
        // Processing the data received from the server
        fn_license_addon_parse_license_information($data);
 
    }
 
}
 
?>

Check on Add-on Status and License Number Change

In order to perform validation on add-on status and license number change you should extend the settings scheme. Create the folder schemas in the add-on directory. Inside this folder create the subfolder settings with the file actions.post.php with the following 2 functions (download):

addons/licensed_addon_multi/schemas/settings/actions.post.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?php
/***************************************************************************
*                                                                          *
*   (c) 2004 Vladimir V. Kalynyak, Alexey V. Vinokurov, Ilya M. Shalnev    *
*                                                                          *
* This  is  commercial  software,  only  users  who have purchased a valid *
* license  and  accept  to the terms of the  License Agreement can install *
* and use this program.                                                    *
*                                                                          *
****************************************************************************
* PLEASE READ THE FULL TEXT  OF THE SOFTWARE  LICENSE   AGREEMENT  IN  THE *
* "copyright.txt" FILE PROVIDED WITH THIS DISTRIBUTION PACKAGE.            *
****************************************************************************/
 
 
if ( !defined('AREA') ) { die('Access denied'); }
 
// The function validates license on add-on status change
function fn_settings_actions_addons_license_addon(&$new_value, $old_value)
{
    // Receiving response from the server
    $data = fn_license_addon_get_license_information();
    // Checking the response
    fn_license_addon_parse_license_information($data);
 
    return true;
}
 
// The function validates the license on license number change
function fn_settings_actions_addons_license_addon_license_number(&$new_value, $old_value)
{
    // Getting response from the server
    $data = fn_license_addon_get_license_information();
    // Checking the response
    fn_license_addon_parse_license_information($data);
 
    // If the license is not valid:
    if (!fn_license_addon_check_valid()) {
        if (defined(COMPANY_ID)) {
            // In case of storefront-based licensing setting the license status as not valid for a particular storefront
            fn_license_addon_change_status_addon(false, COMPANY_ID);
        }
 
        // Notifying the user about the add-on status being forcibly changed
        fn_set_notification('W', fn_get_lang_var('warning'), fn_get_lang_var('addon_license_invalid'));
    }
 
    return true;
}
 
?>

Access restriction on license validity check fail

In case of one common license for all storefronts an add-on is simply deactivated if a license validity check fails.

In the case of separate storefront-based licensing an add-on can not be deactivated, and it is necessary to insert the following code at the beginning of every file to have restricted access to:

1
if (!fn_license_addon_check_valid()) { return false; }

For example, the modified auth.post.php file might look similar to this (download):

addons/licensed_addon_multi/controllers/admin/auth.post.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
 
if ( !defined('AREA') ) { die('Access denied'); }
 
if (!fn_license_addon_check_valid()) { return false; }
 
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
 
    if ($mode == 'login') {
 
        // Requesting license data from the server
        $data = fn_license_addon_get_license_information();
 
        // Processing the data received from the server
        fn_license_addon_parse_license_information($data);
 
    }
 
}
 
?>
Home / Docs / Add-ons / Tutorials / Storefront-Based Add-on Licensing in Ultimate Edition