How do I configure server-side serial number validation?

The best approach for validating a serial number entered by an user is a server-side validation. Basically, the package will send specific information to your server, which will verify the received information and it will return an answer.

NoteThe information is sent to the server by using the POST method (not the "GET" method).

Each piece of information retrieved from the user is stored into an installer property:

  • serial number -> PIDKEY
  • user name -> USERNAME
  • company -> COMPANYNAME
  • package version -> ProductVersion
  • email -> EMAIL
  • the ID of the system language -> it is retrieved automatically by the custom action which sends the information
  • additional information -> ADD_SV_INFO

The script which gets and verifies this information uses the following variables: sn (serial number), username, company, email, version, languageid and ai (additional information). After this information is verified, the server will return a reply which looks like this:

AnswerCode\nMessage

AnswerCode represents the result of the server-side validation and it can be:

  • 601 - the serial number is valid and the installation will continue
  • 602 - the serial number is not valid and the installation will stop

Message is a string sent by the server to explain why the serial number is invalid. This message is showed to the user only if the AnswerCode is different from 601.

NoteOptionally, you can return a custom AnswerCode in case you consider the received serial number as valid and want to dynamically change the course of installation according to this response. The AnswerCode sent by the server after the validation will be available by accessing the Windows Installer property AI_SERVAL_RESPONSE_CODE. For example, you can choose to conditionally install a feature based on the response code received from your server-side validation script; you could have several classes of valid serial numbers and your installation package can deploy differently depending on which serial number the user has entered.

For example, a reply from the server can look like this:

602\nThe serial number is invalid.

In this case, the information provided by the user was not found in the database and the server replied for an invalid serial number.

Or, you can respond by a custom message:

555\nThe serial number you registered will only allow you access to the Main application module.

In this case, the serial number provided was considered valid, but some product functionality will not be installed or activated.

Create the database on the server

Since the validation is performed on your server, you can use a database to keep track of your customers and their serial numbers. A sample MySQL script is this:

CREATE DATABASE IF NOT EXISTS `mydb` DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
USE `mydb`;

-- --------------------------------------------------------
--
-- Table structure for table `clients`
--

CREATE TABLE IF NOT EXISTS `clients` (
  `client_id` int(10) unsigned NOT NULL auto_increment,
  `user_name` varchar(255) collate utf8_bin NOT NULL,
  `company` varchar(255) collate utf8_bin NOT NULL,
  `email` varchar(255) collate utf8_bin NOT NULL,
  `serial_no` varchar(255) collate utf8_bin NOT NULL,
  `additional_information` TEXT collate utf8_bin NOT NULL,
  PRIMARY KEY  (`client_id`),
  UNIQUE KEY `email` (`email`),
  UNIQUE KEY `serial` (`serial_no`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Our company clients' AUTO_INCREMENT=3 ;

--
-- Dumping data for table `clients`
--

INSERT INTO `clients` (`client_id`, `user_name`, `company`, `email`, `serial_no`, `additional_information`) VALUES
(1, 'John Doe', 'User Comp.', 'johnd@domain.com', '233-421-752-325', 'additional information'),
(2, 'User Name', 'Home', 'email@domain.com', '444-555-222-243', 'additional information');

This database will be queried by a script in order to determine if the serial number of the user which runs the installation is valid.

Create the script which verifies the serial number

This script must be able to receive the information sent by the installer, connect to the database, verify the information and issue a response. Here is a sample PHP script:

<?php
// server response codes
define('LICENSE_VALID',   '601');
define('LICENSE_INVALID', '602');

$config = [
  // database connection parameters
  'database' => [
    'name' => 'mydb',
    'username' => 'root',
    'password' => '',
    'connection' => 'mysql:host=localhost',
    // set the PDO error mode to exception
    'options' => [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    ]
  ],
  // client information table
  'clientsTableName' => 'clients',
  'serialNoTableCol' => 'serial_no'
];

/**
 * Server HTTP response to the query issued by Advanced Installer serial validation tool.
 *
 * @param boolean $isValid
 * @param string $postedSerial
 * @param int $languageId
 * @return string
 */
function serverResponse($isValid, $postedSerial = '', $languageId = 1033) {
  $newLine = "\n";

  // load error messages from your database, using "$languageId" for localization (optional)

  if ($postedSerial == '') {
    return LICENSE_INVALID . $newLine . 'Missing Serial Number!';
  }

  if ($isValid) {
    return LICENSE_VALID;
  } else {
    return LICENSE_INVALID . $newLine . 'Serial Number: ' . $postedSerial . ' is invalid!';
  }
}

/**
 * Connect to the database using PDO.
 * 
 * @param array $config
 * @return PDO
 */
function openDbConnection($config, $serialNumber, $languageId) {
  try {
    $connection = new PDO(
      $config['connection'] . ';dbname=' . $config['name'],
      $config['username'],
      $config['password'],
      $config['options']
    );

    return $connection;
  } catch (PDOException $exception) {
    echo serverResponse(false, $serialNumber, $languageId);
    die();
  }
}

/**
 * Get the serial number from database.
 * 
 * @param string $serialNumber
 * @param string $languageId
 * @return int
 */
function getSerialNumber($serialNumber, $languageId) {
  $dbConnection = openDbConnection($GLOBALS['config']['database'], $serialNumber, $languageId);

  // prepare SQL statement
  $serialNumberQuery =  "SELECT `{$GLOBALS['config']['serialNoTableCol']}` FROM `{$GLOBALS['config']['clientsTableName']}` ";
  $serialNumberQuery .= "WHERE `{$GLOBALS['config']['serialNoTableCol']}` = {$dbConnection->quote($serialNumber)}";

  // execute query
  $result = $dbConnection->query($serialNumberQuery)->fetchColumn();

  return $result;
}

/**
 * Validate the given serial number.
 * 
 * @param string $serialNumber
 * @param int $languageId 
 * @param string $additionalInformation
 * @return string
 */
function validateSerialNumber($serialNumber, $languageId, $additionalInformation) {
  $result = getSerialNumber($serialNumber, $languageId);

  // get result set size
  if ($result == 0) {
    // serial number NOT found in database => issue error response
    echo serverResponse(false, $serialNumber, $languageId);
    die();
  } else {
    // serial number was found in database => issue SUCCESS response
    echo serverResponse(true, $serialNumber, $languageId);
    die();
  }
}

// Variables POSTed by Advanced Installer serial validation tool to this web page: "sn", "languageid".
if (isset($_POST['sn']) && trim($_POST['sn']) != '') {
  // get the serial number entered by the installing user in the "UserRegistrationDlg" dialog
  $serialNumber = trim($_POST['sn']);

  // get the system language ID of the user's machine
  // (you can use this parameter to display a localized error message taken from your database)
  $languageId = (int) $_POST['languageid'];

  // get the additional information entered by the installing user in the "UserRegistrationDlg" dialog
  $additionalInformation = $_POST['ai'];

  validateSerialNumber($serialNumber, $languageId, $additionalInformation);
} else {
  // issue error response
  echo serverResponse(false);
  die();
}
?>
      

This script must be placed on your server in a URL which will be accessed by the installation package. For example, if the PHP script is named "validate.php" then the URL can be something like this:

http://www.example.com/validate.php

NoteYou can download an example which uses a PHP or JSP script over a MySQL database.

Caution!If the targeted computer for installation does not have internet connectivity, the provided URL is incorrect or the web sever does not respond in a timely fashion with the appropriate message format, the Advanced Installer validation tool will not allow the installation to continue.

Limited number of activations (serial number validations)

A common scenario would be to limit the number of successful serial validations. Suppose that each of your customers has purchased a certain number of licenses and when this number of installations is reached, future installations should fail with an appropriate error message (for instance, "Maximum number of validations exceeded" instead of "Invalid serial number").

Basically, considering the above example, you can add 2 more columns to the "clients" table:

  • license_no - will hold the number of licenses each user has purchased
  • validations_no - will hold the number of successful serial number validations for each user (basically, it will specify the number of times a given serial number was used)

Each time a valid serial is POST-ed to the script, the value of the "validations_no" column is incremented and compared with the value of the "license_no" column. If the number of successful validations has been exceeded, the answer code "602" is sent with an appropriate error message ("Maximum number of validations exceeded"), causing the installation to be stopped.

You will find modified PHP and MySQL scripts, implementing the approach discussed above, in the "RegLimit" folder inside the provided zip archive.

Configure the installer project

In order to configure the installation package you can follow these steps:

  1. go to the Serial Validation Page
  2. check the Use Serial Validation option
  3. select the Server-side validation validation method
  4. set the URL which points to the PHP script (http://www.example.com/validate.php)
  5. set the Template Value for the serial number

ImportantThe validation of the serial number will be executed twice: during the Wizard Dialogs Stage after the data is collected from the user and during the Install Execution Stage when the application is being installed. In order to Validate serial number during Wizard Dialogs Stage only these modifications must be added into the project.

When enabling the serial validation feature Advanced Installer automatically adds the "UserRegistrationDlg" dialog in the Dialogs page. This dialog contains three edit box controls which set the PIDKEY, USERNAME and COMPANYNAME properties.

NoteThese properties can also be set from the command line when performing a silent (or normal) installation.

Below there is link to a short video with the steps enumerated above.