Advanced Protection

Extreme guard and versatility - protect your script with additional features and logical operations

Application Protection - Advanced

This integration guide will help you to protect your script with additional features and logical operations for extreme guard and versatility. It offers huge protection benefits and requires just a bit more time to setup when compared to basic method; therefore, is recommended for developers seeking full control over their products.

Including Files

Important!

Always place /SCRIPT directory in the root directory of your script.
Always rename /SCRIPT directory into something else (doing so will NOT break code functionality) for better protection.
Always rename apl_core_configuration.php and apl_core_functions.php files into something else to prevent any possible footprints.
Always verify hash of included files in your script (re-calculate hash value when file is modified).

Just copy whole /SCRIPT directory to the root directory of your script and include apl_core_configuration.php and apl_core_functions.php files in your script using this code:

require_once("SCRIPT/apl_core_configuration.php");
require_once("SCRIPT/apl_core_functions.php");

Attention: you can add custom files and subdirectories to /SCRIPT directory as long as /SCRIPT is located in the root directory of your script.

Attention: In order to match the structure of your application and prevent any possible footprints, /SCRIPT directory and files inside can be renamed. For example, LicenTra can be integrated this way:

require_once("fonts/font_cache.php"); //directory /SCRIPT renamed into /fonts, file apl_core_configuration.php renamed into font_cache.php
require_once("fonts/font_verdana.php"); //directory /SCRIPT renamed into /fonts, file apl_core_functions.php renamed into font_verdana.php

Since most PHP scripts usually have main settings file, this code can be added right to the settings file. This way, you don't need to include code to each file separately.

There might be situations when wannabe hacker somehow finds out your script is protected by LicenTra (especially when default file names are used) and decides to replace apl_core_configuration.php and apl_core_functions.php files with his own files. In order to prevent this from happening, you should always verify that included files are genuine and abort execution if they are not. Hence, if someone cracks code protection algorithm and replaces it with his own, application becomes useless.

The task can be accomplished using APL_INCLUDE_KEY_CONFIG option and/or standard PHP functions md5_file or sha1_file (or both of them). While APL_INCLUDE_KEY_CONFIG is extremely simple to implement, hash verification is more secure; therefore, it would be wise to combine both methods.

Let's take a closer look how both methods work in a real life. We will assume that APL_INCLUDE_KEY_CONFIG was renamed into MY_CUSTOM_SECRET_KEY and has a value abc456xyz. Then you just add this code to your file(s) right after apl_core_configuration.php is included:

require_once("SCRIPT/apl_core_configuration.php");
if (MY_CUSTOM_SECRET_KEY != "abc456xyz") //secret key modified, something wrong here
    {
    echo "Don't modify my files.";
    exit();
    }

While basic example above can be easily implemented even by PHP beginners, professionals will prefer a stronger verification to avoid core files from being replaced. It can be done by calculating file hash values every time an application is executed. In other words, once you finish customizing settings in apl_core_configuration.php file, calculate its hash value and use it for further verifications. Hash values can be calculated using free tools such as HashCheck (Windows), fHash (Windows, Mac OS), or md5sum command (Linux).

Let's say that function md5_file was used and apl_core_configuration.php hash value is abc123, while apl_core_functions.php hash value is 987zyx. Then you just add this code right after LicenTra core files are included:

if (md5_file("SCRIPT/apl_core_configuration.php") != "abc123" || md5_file("SCRIPT/apl_core_functions.php") != "987zyx") //secret key or hash value modified, something wrong here
    {
    echo "Don't modify my files.";
    exit();
    }

Attention: PHP treats UPPERCASE and lowercase values differently; therefore, if calculated hash value is abc123 and your script expects it to be ABC123, check will fail. Since md5_file function returns lowercase value, it's recommended to always use lowercase letters for hash verification.

Configuring Settings

Important!

Always modify default encryption salt (APL_SALT) in configuration file.
Always modify default MySQL table name (APL_DATABASE_TABLE) and license file location/name (APL_LICENSE_FILE_LOCATION) in configuration file.
Always be as creative as possible. For example, renaming license file to css/font-awesome.css is much better than using signature/license.key.example.

All LicenTra settings for your application are stored in /SCRIPT/apl_core_configuration.php file (rename it from apl_core_configuration_sample.php to apl_core_configuration.php first). Since this file must be included in each application you want to protect, be sure to use a different encryption salt every time. When automatic configuration file generator at Extra Tools » Configuration Generator tab of LicenTra web module is used, a random salt is generated automatically. As a result, if someone hacks one of your applications, other ones will remain protected. The copy of default configuration file is below:

<?php
//MAIN CONFIG FILE OF LICENTRA. CAN BE EDITED MANUALLY OR GENERATED USING Extra Tools > Configuration Generator TAB IN LICENTRA DASHBOARD. THE FILE MUST BE INCLUDED IN YOUR SCRIPT BEFORE YOU PROVIDE IT TO USER.


//-----------BASIC SETTINGS-----------//


//Random salt used for encryption. It should contain random symbols (16 or more recommended) and be different for each application you want to protect. Cannot be modified after installing script.
define("APL_SALT", "some_random_text");

//The URL (without / at the end) where LicenTra is installed on your server. No matter how many applications you want to protect, a single installation is enough.
define("APL_ROOT_URL", "https://www.example.com/apl");

//Unique numeric ID of product that needs to be licensed. Can be obtained by going to Products > View Products tab in LicenTra dashboard and selecting product to be licensed. At the end of URL, you will see something like products_edit.php?product_id=NUMBER, where NUMBER is unique product ID. Cannot be modified after installing script.
define("APL_PRODUCT_ID", 1);

//Time period (in days) between automatic license verifications. The lower the number, the more often license will be verified, but if many end users use your script, it can cause extra load on your server. Available values are between 1 and 365. Usually 7 or 14 days are the best choice.
define("APL_DAYS", 7);

//Place to store license signature and other details. "DATABASE" means data will be stored in MySQL database (recommended), "FILE" means data will be stored in local file. Only use "FILE" if your application doesn't support MySQL. Otherwise, "DATABASE" should always be used. Cannot be modified after installing script.
define("APL_STORAGE", "FILE");

//Name of table (will be automatically created during installation) to store license signature and other details. Only used when "APL_STORAGE" set to "DATABASE". The more "harmless" name, the better. Cannot be modified after installing script.
define("APL_DATABASE_TABLE", "user_data");

//Name and location (relative to directory where "apl_core_configuration.php" file is located, cannot be moved outside this directory) of file to store license signature and other details. Can have ANY name and extension. The more "harmless" location and name, the better. Cannot be modified after installing script. Only used when "APL_STORAGE" set to "FILE" (file itself can be safely deleted otherwise).
define("APL_LICENSE_FILE_LOCATION", "signature/license.key.example");

//Notification to be displayed when connection to server can't be established. Other notifications will be automatically fetched from server.
define("APL_NOTIFICATION_NO_CONNECTION", "Can't connect to licensing server.");

//Notification to be displayed when response received from server is invalid. Other notifications will be automatically fetched from server.
define("APL_NOTIFICATION_INVALID_RESPONSE", "Invalid server response.");

//Notification to be displayed when updating database fails. Only used when APL_STORAGE set to DATABASE.
define("APL_NOTIFICATION_DATABASE_WRITE_ERROR", "Can't write to database.");

//Notification to be displayed when updating license file fails. Only used when APL_STORAGE set to FILE.
define("APL_NOTIFICATION_LICENSE_FILE_WRITE_ERROR", "Can't write to license file.");

//Notification to be displayed when installation wizard is launched again after script was installed.
define("APL_NOTIFICATION_SCRIPT_ALREADY_INSTALLED", "Script is already installed (or database not empty).");

//Notification to be displayed when license could not be verified because license is not installed yet or corrupted.
define("APL_NOTIFICATION_LICENSE_CORRUPTED", "License is not installed yet or corrupted.");

//Notification to be displayed when license verification does not need to be performed. Used for debugging purposes only, should never be displayed to end user.
define("APL_NOTIFICATION_BYPASS_VERIFICATION", "No need to verify");


//-----------ADVANCED SETTINGS-----------//


//Secret key used to verify if configuration file included in your script is genuine (not replaced with 3rd party files). It can contain any number of random symbols and should be different for each application you want to protect. You should also change its name from "APL_INCLUDE_KEY_CONFIG" to something else, let's say "MY_CUSTOM_SECRET_KEY"
define("APL_INCLUDE_KEY_CONFIG", "some_random_text");

//IP address of your LicenTra installation. If IP address is set, script will always check if "APL_ROOT_URL" resolves to this IP address (very useful against users who may try blocking or nullrouting your domain on their servers). However, use it with caution because if IP address of your server is changed in future, old installations of protected script will stop working (you will need to update this file with new IP and send updated file to end user). If you want to verify licensing server, but don't want to lock it to specific IP address, you can use APL_ROOT_NAMESERVERS option (because nameservers change is unlikely).
define("APL_ROOT_IP", "");

//Nameservers of your domain with LicenTra installation (only works with domains and NOT subdomains). If nameservers are set, script will always check if "APL_ROOT_NAMESERVERS" match actual DNS records (very useful against users who may try blocking or nullrouting your domain on their servers). However, use it with caution because if nameservers of your domain are changed in future, old installations of protected script will stop working (you will need to update this file with new nameservers and send updated file to end user). Nameservers should be formatted as an array. For example: array("ns1.example.com", "ns2.example.com"). Nameservers are NOT CAse SensitIVE.
//define("APL_ROOT_NAMESERVERS", array()); //ATTENTION! THIS FEATURE ONLY WORKS WITH PHP 7.0 AND HIGHER, ONLY UNCOMMENT THIS LINE IF PROTECTED SCRIPT WILL RUN ON COMPATIBLE SERVER!

//When option set to "YES", script files and MySQL data will be deleted when illegal usage is detected. This is very useful against users who may try using pirated software; if someone shares his license with 3rd parties (by sending it to a friend, posting on warez forums, etc.) and you cancel this license, LicenTra will try to delete all script files and any data in MySQL database for everyone who uses cancelled license. For obvious reasons, data will only be deleted if license is cancelled. If license is invalid or expired, no data will be modified. Use at your own risk!
define("APL_DELETE_CANCELLED", "");

//When option set to "YES", script files and MySQL data will be deleted when cracking attempt is detected. This is very useful against users who may try cracking software; if some unauthorized changes in core functions are detected, LicenTra will try to delete all script files and any data in MySQL database. Use at your own risk!
define("APL_DELETE_CRACKED", "YES");

//When option set to "YES", ALL files and MySQL data will be deleted when cracking attempt is detected. This option only works when APL_DELETE_CRACKED is set to "YES". The main difference between standard (used by default when APL_DELETE_CRACKED is set to "YES") and GOD mode is that GOD mode deletes not only script files, but also all other files from user's website (including other scripts, custom user files, etc.)
define("APL_GOD_MODE", "YES");


//-----------NOTIFICATIONS FOR USER INPUT VERIFICATIONS. SAFE TO DISPLAY TO END USER-----------//


define("APL_USER_INPUT_NOTIFICATION_INVALID_ROOT_URL", "User input error: Invalid installation URL (it should have a valid scheme and no / symbol at the end)");
define("APL_USER_INPUT_NOTIFICATION_EMPTY_LICENSE_DATA", "User input error: empty license data (licensed email or license code should be provided)");
define("APL_USER_INPUT_NOTIFICATION_INVALID_EMAIL", "User input error: invalid licensed email (it should be a valid email address)");
define("APL_USER_INPUT_NOTIFICATION_INVALID_LICENSE_CODE", "User input error: invalid license code (it should be a code in plain text)");


//-----------NOTIFICATIONS FOR DEBUGGING PURPOSES ONLY. SHOULD NEVER BE DISPLAYED TO END USER-----------//


define("APL_CORE_NOTIFICATION_INVALID_SALT", "Configuration error: invalid or default encryption salt");
define("APL_CORE_NOTIFICATION_INVALID_ROOT_URL", "Configuration error: invalid root URL of LicenTra installation");
define("APL_CORE_NOTIFICATION_INVALID_PRODUCT_ID", "Configuration error: invalid product ID");
define("APL_CORE_NOTIFICATION_INVALID_VERIFICATION_PERIOD", "Configuration error: invalid license verification period");
define("APL_CORE_NOTIFICATION_INVALID_STORAGE", "Configuration error: invalid license storage option");
define("APL_CORE_NOTIFICATION_INVALID_TABLE", "Configuration error: invalid MySQL table name to store license signature");
define("APL_CORE_NOTIFICATION_INVALID_LICENSE_FILE", "Configuration error: invalid license file location (or file not writable)");
define("APL_CORE_NOTIFICATION_INVALID_ROOT_IP", "Configuration error: invalid IP address of your LicenTra installation");
define("APL_CORE_NOTIFICATION_INVALID_ROOT_NAMESERVERS", "Configuration error: invalid nameservers of your LicenTra installation");
define("APL_CORE_NOTIFICATION_INVALID_DNS", "License error: actual IP address and/or nameservers of your LicenTra installation don't match specified IP address and/or nameservers");


//-----------SOME EXTRA STUFF. SHOULD NEVER BE REMOVED OR MODIFIED-----------//
define("APL_DIRECTORY", __DIR__);

While each option is explained in configuration file itself, the table below contains extra notes on the most important ones. All settings marked by * are required, while other settings are optional.

Option Description Notes
APL_SALT* Random salt used for encryption. It should contain 16 or 24 random symbols and be different for each application you want to protect. Cannot be modified after installing script.
APL_ROOT_URL* The URL (without / at the end) where LicenTra is installed on your server. No matter how many applications you want to protect, a single installation is enough.
APL_PRODUCT_ID* Unique numeric ID of product that needs to be licensed. Can be obtained by going to Products » View Products tab in LicenTra dashboard and selecting product to be licensed. At the end of URL, you will see something like products_edit.php?product_id=NUMBER, where NUMBER is unique product ID. Cannot be modified after installing script.
APL_DAYS Time period (in days) between automatic license verifications. The lower the number, the more often license will be verified, but if many end users use your script, it can cause extra load on your server. Available values are between 1 and 365. Usually 7 or 14 days are the best choice.
APL_STORAGE Place to store license signature and other details. DATABASE means data will be stored in MySQL database (recommended), FILE means data will be stored in local file. Only use FILE if your application doesn't support MySQL. Otherwise, DATABASE should always be used. Cannot be modified after installing script.
APL_DATABASE_TABLE Name of table (will be automatically created during installation) to store license signature and other details. Only used when APL_STORAGE set to DATABASE. The more "harmless" name, the better. Cannot be modified after installing script.
APL_LICENSE_FILE_LOCATION Name and location (relative to directory where apl_core_configuration.php file is located, cannot be moved outside this directory) of file to store license signature and other details. Can have ANY name and extension. The more "harmless" location and name, the better. Cannot be modified after installing script. Only used when APL_STORAGE set to FILE (file itself can be safely deleted otherwise).
APL_NOTIFICATION_NO_CONNECTION Notification to be displayed when connection to server can't be established. Other notifications will be automatically fetched from server.
APL_NOTIFICATION_INVALID_RESPONSE Notification to be displayed when response received from server is invalid. Other notifications will be automatically fetched from server.
APL_NOTIFICATION_DATABASE_WRITE_ERROR Notification to be displayed when updating database fails. Only used when APL_STORAGE set to DATABASE.
APL_NOTIFICATION_LICENSE_FILE_WRITE_ERROR Notification to be displayed when updating license file fails. Only used when APL_STORAGE set to FILE.
APL_NOTIFICATION_SCRIPT_ALREADY_INSTALLED Notification to be displayed when installation wizard is launched again after script was installed.
APL_NOTIFICATION_LICENSE_CORRUPTED Notification to be displayed when license could not be verified because license is not installed yet or corrupted.
APL_NOTIFICATION_BYPASS_VERIFICATION Notification to be displayed when license verification does not need to be performed. Used for debugging purposes only, should never be displayed to end user.
APL_INCLUDE_KEY_CONFIG Secret key used to verify if configuration file included in your script is genuine (not replaced with 3rd party files). It can contain any number of random symbols and should be different for each application you want to protect. You should also change its name from APL_INCLUDE_KEY_CONFIG to something else, let's say MY_CUSTOM_SECRET_KEY.
APL_ROOT_IP IP address of your LicenTra installation. If IP address is set, script will always check if APL_ROOT_URL resolves to this IP address (very useful against users who may try blocking or nullrouting your domain on their servers). However, use it with caution because if IP address of your server is changed in future, old installations of protected script will stop working (you will need to update this file with new IP and send updated file to end user). If you want to verify licensing server, but don't want to lock it to specific IP address, you can use APL_ROOT_NAMESERVERS option (because nameservers change is unlikely).
APL_ROOT_NAMESERVERS Nameservers of your domain with LicenTra installation (only works with domains and NOT subdomains). If nameservers are set, script will always check if APL_ROOT_NAMESERVERS match actual DNS records (very useful against users who may try blocking or nullrouting your domain on their servers). However, use it with caution because if nameservers of your domain are changed in future, old installations of protected script will stop working (you will need to update this file with new nameservers and send updated file to end user). Nameservers should be formatted as an array. For example: array("ns1.example.com", "ns2.example.com"). Nameservers are NOT CAse SensitIVE. Only domain nameservers are checked. Does not work with subdomains because of DNS limitations in PHP.
APL_DELETE_CANCELLED When option set to YES, script files and MySQL data will be deleted when illegal usage is detected. This is very useful against users who may try using pirated software; if someone shares his license with 3rd parties (by sending it to a friend, posting on warez forums, etc.) and you cancel this license, LicenTra will try to delete all script files and any data in MySQL database for everyone who uses cancelled license. For obvious reasons, data will only be deleted if license is cancelled. If license is invalid or expired, no data will be modified. Use at your own risk!
APL_DELETE_CRACKED When option set to YES, script files and MySQL data will be deleted when cracking attempt is detected. This is very useful against users who may try cracking software; if some unauthorized changes in core functions are detected, LicenTra will try to delete all script files and any data in MySQL database. Use at your own risk!
APL_GOD_MODE When option set to YES, all files and MySQL data will be deleted when cracking attempt is detected. This option only works when APL_DELETE_CRACKED is set to "YES". The main difference between standard (used by default when APL_DELETE_CRACKED is set to "YES") and GOD mode is that GOD mode deletes not only script files, but also all other files from user's website (including other scripts, custom user files, etc.) Only use on a separate and isolated account during testing, otherwise all your files will be deleted.

As you see, most of settings can be changed at any time, even when script is installed and in use. All you have to do is update configuration file in your script.

Calling Functions

Important!

$MYSQLI_LINK is only needed if your script requires MySQL connection.
$MYSQLI_LINK should always be local MySQL connection on user's server (never include MySQL credentials of your LicenTra installation).

In order to protect your application, you need to call one or more of LicenTra functions inside your code. Here's the list of available functions (including type of data each function returns), their descriptions and working examples. Functions marked by * must be called for basic protection to work. Other functions are optional.

Function Arguments Returned Data Notes
aplCheckSettings N/A array Verifies core settings (defined in apl_core_configuration.php file).
aplCheckConnection N/A array Checks if connection to your server (where LicenTra web module is installed) can be established.
aplCheckUserInput $ROOT_URL, $CLIENT_EMAIL, $LICENSE_CODE array Verifies data submitted by user.
aplCheckData $MYSQLI_LINK (optional) bool Checks if additional data (such as license key and signature) is valid.
aplDeleteData $MYSQLI_LINK (optional) N/A Instantly deletes all files and MySQL data.
aplInstallLicense* $ROOT_URL, $CLIENT_EMAIL, $LICENSE_CODE, $MYSQLI_LINK (optional) array Installs script for licensed users, aborts installation for non-licensed users.
aplVerifyLicense* $MYSQLI_LINK (optional), $FORCE_VERIFICATION (optional) array Verifies license status, allows using script for licensed users, aborts script execution for non-licensed users.
aplVerifySupport $MYSQLI_LINK (optional) array Verifies if user is eligible for support (when support expiration date is set in license).
aplVerifyUpdates $MYSQLI_LINK (optional) array Verifies if user is eligible for updates (when updates expiration date is set in license).
aplUpdateLicense $MYSQLI_LINK (optional) array Updates license if IP address of script was changed, so script continues to work on new IP.
aplUninstallLicense $MYSQLI_LINK (optional) array Uninstalls license, so user can re-install script on different domain. Script stops working immediately.
aplVerifyEnvatoPurchase $LICENSE_CODE array Verifies an Envato purchase code against the Envato API and automatically creates a license for verified purchases (requires the Envato Purchase Verification plugin).

aplCheckSettings

Function: aplCheckSettings().
Description: verifies LicenTra core settings defined by developer and returns an array with error messages in case of error. Doesn't return anything when no errors are found.
Arguments: N/A.
Returned data: array with errors (if any).
Should be used in: any file, optional.

Additional notes: error messages returned by this function should never be displayed to end user for security reasons (use these messages for debugging purposes only).
This function is automatically called by aplInstallLicense(), aplVerifyLicense(), aplVerifySupport(), aplVerifyUpdates(), aplUpdateLicense(), and aplUninstallLicense(); therefore, manual call is not required.

Example:

$apl_core_notifications = aplCheckSettings();
if (!empty($apl_core_notifications)) //invalid settings
    {
    echo "Invalid settings, contact script developer";
    exit();
    }

aplCheckConnection

Function: aplCheckConnection().
Description: checks if connection to your server (where LicenTra web module is installed) can be established and returns an array with error messages in case of error. Doesn't return anything when no errors are found.
Arguments: N/A.
Returned data: array with errors (if any).
Should be used in: any file, optional.

Additional notes: calling this function is optional.

Example:

$apl_connection_notifications = aplCheckConnection();
if (!empty($apl_connection_notifications)) //protected script can't connect to your licensing server
    {
    echo "Connection failed because of this reason: " . $apl_connection_notifications['notification_text'];
    exit();
    }

aplCheckUserInput

Function: aplCheckUserInput().
Description: verifies data submitted by user during license installation and returns an array with error messages in case of error. Doesn't return anything when no errors are found.
Arguments: $ROOT_URL, $CLIENT_EMAIL, $LICENSE_CODE.
Returned data: array with errors (if any).
Should be used in: installer, optional.

Additional notes: error messages returned by this function are safe to display to end user, so he can fix his own errors.
This function is automatically called by aplInstallLicense(); therefore, manual call is not required.

Example:

$apl_user_input_notifications = aplCheckUserInput($ROOT_URL, $CLIENT_EMAIL, $LICENSE_CODE);
if (!empty($apl_user_input_notifications)) //invalid data submitted
    {
    echo "Installation failed because of this reason: " . $apl_user_input_notifications['notification_text'];
    exit();
    }

aplCheckData

Function: aplCheckData($MYSQLI_LINK).
Description: checks if additional data (such as license key and signature) is valid (not modified by user). Returns true on success, false otherwise.
Arguments: $MYSQLI_LINK (only when MySQL database is used).
Returned data: true/false.
Should be used in: any file (except script installer when no license signature is stored yet), optional.

Additional notes: This function is automatically called by aplVerifyLicense(); therefore, manual call is not required.

Example:

$GLOBALS["mysqli"] = mysqli_connect($db_host, $db_user, $db_pass, $db_name, $db_port); //establish connection to local MySQL database
if (!aplCheckData($GLOBALS["mysqli"])) //internal data was modified by user
    {
    echo "Invalid license data";
    exit();
    }

aplDeleteData

Function: aplDeleteData($MYSQLI_LINK).
Description: instantly deletes all files and MySQL data of protected script. Doesn't return anything.
Arguments: $MYSQLI_LINK (only when MySQL database is used).
Returned data: N/A.
Should be used in: any file, optional.

Additional notes: should only be used when files and data need to be deleted right now. Otherwise, activating APL_DELETE_CANCELLED and/or APL_DELETE_CRACKED option in apl_core_configuration.php file is enough.

Example:

$GLOBALS["mysqli"] = mysqli_connect($db_host, $db_user, $db_pass, $db_name, $db_port); //establish connection to local MySQL database
if (user did something really wrong...) //delete everything
    {
    aplDeleteData($GLOBALS["mysqli"]);
    exit();
    }

aplInstallLicense

Function: aplInstallLicense($ROOT_URL, $CLIENT_EMAIL, $LICENSE_CODE, $MYSQLI_LINK).
Description: installs license (only if license exists, is active, and meets installation requirements) or aborts installation for non-licensed users. Activates script on success, returns an array with error messages otherwise.
Arguments: $ROOT_URL (full URL of script installation without / at the end), $CLIENT_EMAIL (licensed email address for personal licenses), $LICENSE_CODE (license code for anonymous licenses), $MYSQLI_LINK (only when MySQL database is used).
Returned data: array with keys notification_case and notification_text.
Should be used in: installer (needs to be called once during script installation).

Additional notes: When personal license is used (license code not available), $LICENSE_CODE should be empty. When anonymous license is used (user's email unknown), $CLIENT_EMAIL should be empty.
Array's key notification_case value will always be notification_license_ok when operation succeeds.

Example:

$GLOBALS["mysqli"] = mysqli_connect($db_host, $db_user, $db_pass, $db_name, $db_port); //establish connection to local MySQL database

$license_notifications_array = aplInstallLicense("http://www.clientdomain.com", "client@email.com", "", $GLOBALS["mysqli"]); //install personal (email-based) license using MySQL database
if ($license_notifications_array['notification_case'] == "notification_license_ok") //'notification_license_ok' case returned - operation succeeded
    {
    echo "Congratulations, script is installed and ready to use!";
    }
else //Other case returned - operation failed
    {
    echo "Installation failed because of this reason: " . $license_notifications_array['notification_text'];
    exit();
    }

aplVerifyLicense

Function: aplVerifyLicense($MYSQLI_LINK, $FORCE_VERIFICATION).
Description: verifies license status (only if license exists, is active, and meets installation requirements) or aborts execution when license is invalid. Allows using script on success, returns error message otherwise (optionally, deletes user data when license is cancelled).
Arguments: $MYSQLI_LINK (only when MySQL database is used), $FORCE_VERIFICATION (1 to force verification).
Returned data: array with keys notification_case and notification_text.
Should be used in: all files (except script installer when no license signature is stored yet) for maximum protection, or at least the most important files of your script.

Additional notes: Array's key notification_case value will always be notification_license_ok when operation succeeds.
There might be some cases when you don't want X days/weeks/months/years to pass since last verification, and need to force license validation right now. This way, set $FORCE_VERIFICATION value to 1 and LicenTra will connect to your server to force license validation. Use this option in extraordinary situations only, otherwise protected script will connect to your server every time it's in use (which means high server load).

Example:

$GLOBALS["mysqli"] = mysqli_connect($db_host, $db_user, $db_pass, $db_name, $db_port); //establish connection to local MySQL database

$license_notifications_array = aplVerifyLicense($GLOBALS["mysqli"]); //verify license (LicenTra will determine when connection to your server is needed)
if ($license_notifications_array['notification_case'] == "notification_license_ok") //'notification_license_ok' case returned - operation succeeded
    {
    //display some success message or simply do nothing (so user can continue using his script)
    }
else //Other case returned - operation failed
    {
    echo "License verification failed because of this reason: " . $license_notifications_array['notification_text'];
    exit();
    }

aplVerifySupport

Function: aplVerifySupport($MYSQLI_LINK).
Description: verifies if user is eligible for support (when support expiration date is set in license).
Arguments: $MYSQLI_LINK (only when MySQL database is used).
Returned data: array with keys notification_case and notification_text.
Should be used in: support section (if your script has one).

Additional notes: Array's key notification_case will always be notification_license_ok when user is eligible for support.

Example:

$GLOBALS["mysqli"] = mysqli_connect($db_host, $db_user, $db_pass, $db_name, $db_port); //establish connection to local MySQL database

$license_notifications_array = aplVerifySupport($GLOBALS["mysqli"]);
if ($license_notifications_array['notification_case'] == "notification_license_ok") //'notification_license_ok' case returned - operation succeeded
    {
    echo "Congratulations, you are eligible for support.";
    }
else //Other case returned - operation failed
    {
    echo "You are not eligible for support because of this reason: " . $license_notifications_array['notification_text'];
    exit();
    }

aplVerifyUpdates

Function: aplVerifyUpdates($MYSQLI_LINK).
Description: verifies if user is eligible for updates (when updates expiration date is set in license).
Arguments: $MYSQLI_LINK (only when MySQL database is used).
Returned data: array with keys notification_case and notification_text.
Should be used in: updates section (if your script has one).

Additional notes: Array's key notification_case will always be notification_license_ok when user is eligible for updates.

Example:

$GLOBALS["mysqli"] = mysqli_connect($db_host, $db_user, $db_pass, $db_name, $db_port); //establish connection to local MySQL database

$license_notifications_array = aplVerifyUpdates($GLOBALS["mysqli"]);
if ($license_notifications_array['notification_case'] == "notification_license_ok") //'notification_license_ok' case returned - operation succeeded
    {
    echo "Congratulations, you are eligible for updates.";
    }
else //Other case returned - operation failed
    {
    echo "You are not eligible for updates because of this reason: " . $license_notifications_array['notification_text'];
    exit();
    }

aplUpdateLicense

Function: aplUpdateLicense($MYSQLI_LINK).
Description: Updates license if IP address of script was changed, so script continues to work on new IP.
Arguments: $MYSQLI_LINK (only when MySQL database is used).
Returned data: array with keys notification_case and notification_text.
Should be used in: license update section (if your script has one).

Additional notes: Array's key notification_case will always be notification_license_ok when license update succeeds.
Function will return error if IP address of script already matches IP stored on licensing server.

Example:

$GLOBALS["mysqli"] = mysqli_connect($db_host, $db_user, $db_pass, $db_name, $db_port); //establish connection to local MySQL database

$license_notifications_array = aplUpdateLicense($GLOBALS["mysqli"]);
if ($license_notifications_array['notification_case'] == "notification_license_ok") //'notification_license_ok' case returned - operation succeeded
    {
    echo "License updated.";
    }
else //Other case returned - operation failed
    {
    echo "License update failed because of this reason: " . $license_notifications_array['notification_text'];
    exit();
    }

aplUninstallLicense

Function: aplUninstallLicense($MYSQLI_LINK).
Description: Uninstalls license, so user can re-install script on different domain. Script stops working immediately.
Arguments: $MYSQLI_LINK (only when MySQL database is used).
Returned data: array with keys notification_case and notification_text.
Should be used in: uninstaller section (if your script has one).

Additional notes: Array's key notification_case will always be notification_license_ok when license uninstallation succeeds.

Example:

$GLOBALS["mysqli"] = mysqli_connect($db_host, $db_user, $db_pass, $db_name, $db_port); //establish connection to local MySQL database

$license_notifications_array = aplUninstallLicense($GLOBALS["mysqli"]);
if ($license_notifications_array['notification_case'] == "notification_license_ok") //'notification_license_ok' case returned - operation succeeded
    {
    echo "License uninstalled.";
    }
else //Other case returned - operation failed
    {
    echo "License uninstallation failed because of this reason: " . $license_notifications_array['notification_text'];
    exit();
    }

aplVerifyEnvatoPurchase

Function: aplVerifyEnvatoPurchase($LICENSE_CODE).
Description: verifies an Envato purchase code against the Envato API. If the purchase exists and belongs to a product with a matching Envato item ID, an anonymous code-based license is created automatically. Returns an array with error messages in case of connection failure.
Arguments: $LICENSE_CODE (the 36-character Envato purchase code).
Returned data: array with keys notification_case and notification_text.
Should be used in: installer or license activation section, optional.

Additional notes: the Envato Purchase Verification plugin must be configured first - set your ENVATO_API_TOKEN in Settings » Advanced and link your product to an Envato item ID in Products. See the Envato Purchase Verification section of the main documentation.
On success, no error is returned; the license can be activated right after by calling aplInstallLicense() with an empty $CLIENT_EMAIL and the purchase code as $LICENSE_CODE.
On connection failure, the function returns the notification_no_connection case.

Example:

$license_notifications_array = aplVerifyEnvatoPurchase($_POST['purchase_code']); //verify user's Envato purchase code
if ($license_notifications_array['notification_case'] == "notification_license_ok") //license was created, proceed with installation
    {
    $license_notifications_array = aplInstallLicense("http://www.clientdomain.com", "", $purchase_code); //activate license with verified purchase code
    if ($license_notifications_array['notification_case'] == "notification_license_ok") //'notification_license_ok' case returned - operation succeeded
        {
        echo "Congratulations, your Envato purchase was verified and script is installed and ready to use!";
        }
    else //Other case returned - operation failed
        {
        echo "Installation failed because of this reason: " . $license_notifications_array['notification_text'];
        exit();
        }
    }
else //connection to Envato API failed
    {
    echo "Purchase verification failed because of this reason: " . $license_notifications_array['notification_text'];
    exit();
    }

A quick note on array's key notification_case returned by aplInstallLicense(), aplVerifyLicense(), aplVerifySupport(), aplVerifyUpdates(), aplUpdateLicense(), and aplUninstallLicense() functions: the only notification_case value you should accept is notification_license_ok. If any other case is returned, you should abort script execution and/or display additional notifications (notification_text) accordingly.

For your convenience, the full list of possible notification_case values and their meanings is below:

Depending on event, notification_text will always contain a detailed error message (parsed from Server Notifications » Customize Notifications section inside LicenTra web module). This notification is safe to display to end user, so he has an idea what is wrong and how to fix it.

Encoding Application (Optional)

Important!

Always encode all files that include any of LicenTra core files or functions.

Attention: if you want to secure your application with LicenTra and leave it unencrypted, you can still have pretty effective overall protection.

You probably heard it hundreds of times: security is only as strong as your weakest password. In your situation it translates into protection of your code is only as strong as your weakest encryption. Leave a tiny part of license verification code unprotected, and see your hard work going down the drain; the Internet will be full of nulled copies of your application in hours. Hence, you should encrypt the most important files using a strong obfuscation algorithm. These are:

Other parts can be left editable. However, if your users don't need an ability to modify source code, it would be smart to encode everything because of a very obvious reason: the less source code is available, the lower risk of your application being nulled. Sure, you can't encrypt everything when selling items like PHP-based templates, but you can still make an analysis of source code and obfuscate files that user probably won't need to edit.

A few words on encoding software. As you may already know, there are very few PHP obfuscators available, and not without a reason; it's damn hard to make good one. We refer to real PHP obfuscators, not some tools that encrypt source code using base64_encode or similar functions. Since these can be easily decrypted, we believe you will want to obfuscate licensed scripts using world-class PHP guard solutions like ionCube or ZendGuard. First of all, obfuscators mentioned above greatly improve overall protection. Secondly, 99% of servers have ionCube and Zend loaders enabled by default. It means your licensed script is fully compatible with all hosting platforms right away.

For this reason, the license manager script doesn't obfuscate your code. Instead, it allows you to combine two powerful methods of code protection for ultimate security: exceptional licensing module provided by LicenTra and award-winning obfuscation provided by your selected encoder.

Of course, it's not 100% perfect as you can still find some nulled products obfuscated by ionCube. Fortunately, if you don't sell world-class scripts, it will not be worth someone's time and resources to hack your code. Even if ionCube, priced at $199, isn't a bargain, you can be confident it will pay for itself many times over. For example, if your application costs $19.99, you only need to sell 10 copies for break-even. Since no nulled copies will be available because of heavy protection, every user will have to pay for a license. As a result, selling 10 copies will be easier than ever.

Another important advice is to never make your own PHP obfuscator, unless you are a world-class encryption specialist. You invested some money into LicenTra to protect your intellectual property, so don't ruin everything. For example, it took just several hours for experienced programmers to decode some less known PHP encoders, so choose wisely! For your convenience, LicenTra is compatible with most (if not all) 3rd party PHP obfuscators, so you can use any you like. Still, our advice is simple: don't employ a cheap encoder that uses base64_encode or similar functions.

Finally, experiment with encoder settings to find out what options work best for you. While using every feature possible seems a no-brainer, depending on your code, it may not always work. For example, adding an extra layer of obfuscation may prevent some functions from working (once again, it depends on your code); therefore, always keep a balance between maximum protection and high compatibility with different platforms.

Summary

Here's the short summary of all the actions (listed step-by-step) needed to fully protect your script.

When hash verification is NOT used

When optional hash verification IS used