Custom UAPI Modules

Overview

You can add custom modules to cPanel & WHM and call them with UAPI.

Warning:

Make certain that you thoroughly test custom modules before you attempt to add them to production servers.


Steps to create a custom module

To create a custom module and add it to cPanel & WHM's UAPI, perform the following steps:

  1. Create a Perl module.

Save your custom module as the /usr/local/cpanel/Cpanel/API/Module.pm file, where Module is the custom module's name.

Warning:

UAPI modules reside in the Cpanel::API namespace.

cPanel & WHM treats all of the modules in the /usr/local/cpanel/Cpanel/API/ directory as UAPI modules.

We recommend that you only save module files (.pm) to this location. The presence of other files may cause problems, even if the files relate to your custom modules.


  1. Add functions to your module.
  2. A single module generally contains many functions.
  3. You can cause functions to only work with certain feature lists.
  4. Thoroughly test your module on a non-production server.

Additional resources

For more information about how to write Perl modules, we recommend the following resources:

Create your module

To create a custom module, you must first create the Module.pm file.

Warning:

Make certain that you thoroughly test custom modules before you install them to production servers.


The Module.pm file

Save your custom module as the /usr/local/cpanel/Cpanel/API/Module.pm file, where Module represents the module's name.

Note:
  • We recommend that you use a CamelCase module name.
  • UAPI modules cannot use the same name as an existing UAPI module.
  • UAPI module names should not begin with an underscore ( _ ).

We recommend that you begin with the following file template:

package Cpanel::API::Module;

use strict;

our $VERSION = '1.0';

# Your comments about this custom module.

# Cpanel Dependencies
use Cpanel                   ();
use Cpanel::API              ();
use Cpanel::Locale           ();
use Cpanel::Logger           ();

# Other dependencies go here.
# Defaults go here.
# Constants go here.

# Globals
my $logger;
my $locale;

# Caches go here.

# Functions go here.

1;

Package the module

package Cpanel::API::Module;

This declaration instructs Perl to treat all of the file's functions as a part of the Cpanel::API::Module namespace.

For more information, read perldoc.perl.org's package documentation.

Set the strict pragma

use strict;

This declaration instructs Perl to return errors if the file contains potentially unsafe code.

For more information, read perldoc.perl.org's strict documentation.

Declare a module version

our $VERSION = '1.0';

This declaration creates the variable $VERSION and sets it to 1.0. This allows you to differentiate between this and future versions of your module.

cPanel dependencies

# Cpanel Dependencies
use Cpanel                   ();
use Cpanel::API              ();
use Cpanel::Locale           ();
use Cpanel::Logger           ();

While UAPI calls do not require that you include these dependencies, we recommend that you include them.

For more information, read perldoc.perl.org's use documentation.

Note:

If you include the use Cpanel::API statement, your functions can call functions from any other custom or cPanel-provided UAPI module. Remember that those UAPI functions may have additional feature list requirements.


Additional dependencies, defaults, and constants

# Other dependencies go here.
# Defaults go here.
# Constants go here.

# Globals
my $logger;
my $locale;

# Caches go here.

Use the lines below the Cpanel:: dependencies to declare dependencies on additional Perl modules, declare default values for variables, set constant values, and set caches.

UAPI modules that use the Cpanel::Logger and Cpanel::Locale objects should also declare the $logger and $locale global variables.

Functions

# Functions go here.

Module files must contain at least one function.

For more information, read our Custom Function Basics documentation.

End the module file

End your module file with the following line:

1;
Note:

Perl requires that module files return a true value in order to function. This line fulfills that requirement.


Custom Function Basics

Custom modules contain one or more individual functions.

Warning:

Make certain that you thoroughly test custom modules before you install them to production servers.


Functions

Note:

Write all of the functions for a custom module in the same Module.pm file.

The examples below use the following variables:

  • Module — The custom module's name.
  • function — The name of a function in the custom module.

For each function that you wish to include in your module, we recommend the following format and elements:

#-------------------------------------------------------------------------------------------------
# Name:
#   function - Choose a function name that describes the function's action.
# Desc:
#   A description of the function function's action.
# Arguments:
#   $arg1 - string - A description of the $arg1 parameter.
# Returns:
#   $result1 - string - A description of the $result1 parameter.
#-------------------------------------------------------------------------------------------------
sub function {

    my ( $args, $result ) = @_;
    my ( $arg1, $arg2 ) = $args->get( 'arg1', 'arg2' );

    # (Optional) Set a feature that the cPanel user must have in order to access the function.
    my $feature = 'featurename';                            
    if ( !main::hasfeature($feature) ) {                    
        $result->error( '_ERROR_FEATURE', $feature );
        return;
    }

    # Make the function unusable if the cPanel account is in demo mode.
    if ( $Cpanel::CPDATA{'DEMO'} ) {
        $result->error( '_ERROR_DEMO_MODE', $feature );
        return;
    }

    # Validate the required parameters.
    # Sanitize the arguments.
    # Perform the function's action(s).

    # Build the results.
    if ($success) {
        $result->data($successful_data);
        return 1;
    }
    else {
        return 0;
    }
}

Function information

#-------------------------------------------------------------------------------------------------
# Name:
#   function - Choose a function name that describes the function's action.
# Desc:
#   A description of the function function's action.
# Arguments:
#   $arg1 - string - A description of the $arg1 parameter.
# Returns:
#   $result1 - string - A description of the $result1 parameter.
#-------------------------------------------------------------------------------------------------

We strongly encourage you to include a summary of each function in the form of comments. This practice is beneficial both to your future self, and to other developers who may use your code.

The function subroutine

sub function {

Write each function in a UAPI module as a subroutine.

Note:
  • We recommend that you use lowercase function names.
  • If your function name includes multiple words, separate each word with an underscore ( _ ) for readability.
  • UAPI considers functions with names that begin with an underscore ( _ ) to be private functions.
    • You cannot call these functions through UAPI.
    • These functions will not appear in cPanel's API Shell interface ( cPanel >> Home >> Advanced >> API Shell ).

For more information about subroutines in Perl, read perldoc.perl.org's perlsub documentation.

Get arguments from @_

Important:

We strongly recommend that all custom functions begin with this line of code. Functions that do not perform this action will experience errors.


my ( $args, $result ) = @_;

This code declares the $args and $result variables, and assigns values from @_.

  • The Cpanel::Args object allows UAPI calls to receive named parameters.
  • The Cpanel::Result object allows UAPI calls to return function data.

Use the get() method to assign variables

my ( $arg1, $arg2 ) = $args->get( 'arg1', 'arg2' );

This code assumes that the arg1 and arg2 input parameters exist. It uses the Cpanel::Args object's get() method to assign these parameters' values to the $arg1 and $arg2 variables.

Require a feature

You can choose to require specific features in order to call the function. Replace featurename with the name of the feature to require.

# (Optional) Set a feature that the cPanel user must have in order to access the function.
my $feature = 'featurename';                           
if ( !main::hasfeature($feature) ) {                   
    $result->error( '_ERROR_FEATURE', $feature );
    return;
}

This if statement uses built-in cPanel & WHM functionality to check whether the account has access to the specified feature. If the cPanel user does not have the access to the required feature, the function will return an error message and will not perform any other actions.

For example, the following code requires that a cPanel user has the filemanager feature in order to call the function:

my $feature = 'filemanager';                           
if ( !main::hasfeature($feature) ) {                   
    $result->error( '_ERROR_FEATURE', $feature );
    return;
}

Disallow demo mode

In most cases, you should not allow your custom module to function on cPanel accounts that are in demo mode.

# Make the function unusable if the cPanel account is in demo mode.
if ( $Cpanel::CPDATA{'DEMO'} ) {
    $result->error( '_ERROR_DEMO_MODE', $feature );
    return;
}

This if statement uses built-in cPanel & WHM functionality to check whether the cPanel account is a demo account. If a demo cPanel account attempts to call your function, the function call with return an error message and will not perform any other actions.

Perform the desired actions

# Validate the required parameters.
# Sanitize the arguments.
# Perform the function's action(s).

This section of the subroutine is where your function performs its own unique actions.

These actions could combine any of Perl's many functions. Often, this includes the following actions:

Result data and returns

At the end of your function, you can use the Cpanel::Result object's data() method to assign values to a hash or array of hashes of named output parameters.

  • Output in an array of hashes allows you to use UAPI's filter, sort, and pagination options.
  • The only meaningful return values in Perl are 1 (for success) and 0 (for failure).
  • While Perl allows bare return values, we do not recommend that you use them in UAPI functions. In some circumstances, the system may misinterpret bare return values as true.
    # Build the results.
    if ($success) {
        $result->data($successful_data);
        return 1;
    }
    else {
        return 0;
    }
}

This example code assumes that, at some point during the function's actions, the subroutine initialized and assigned values to the $success and $successful_data values.

Note:

In line 35, this example feeds the $successful_data value into the data hash, to return output parameters. The API also returns the standard UAPI metadata.

If your return data contains any strings with Unicode characters that are binary encoded, and that display on a cPanel interface, you will receive a Wide Character warning. To resolve this, use the following code to encode your strings:

use Encode qw(encode);
$result->data( encode( 'utf-8', $successful_data ) );

The cPanel Args object

UAPI modules use the Cpanel::Args object to receive arguments (input parameters). When you write a custom UAPI module, you must use this object for your functions to operate correctly.

For more information about methods in Perl, read perl.org's perlobj documentation.

Required $args declaration

Before you can use Cpanel::Args methods, you must declare the $args variable, as in the following example:

sub custom_function {
    my ( $args, $result ) = @_;
}

This example declares the $args and $result variables, and assigns values from the input parameters that the function received. We strongly recommend that you begin all custom functions with the my ( $args, $result ) = @_; declaration. Functions that do not perform this action will experience errors.

For more information about the Cpanel::Result object, read the Cpanel::Result Object section below.

Methods

The Cpanel::Args object includes methods that you can use to incorporate input parameter values into your function call.

$args->exists()

This method checks whether a named parameter exists. Use this method, for example, to ensure that a value exists for an input parameter before you attempt to perform the function's action.

# Check whether the param1 input parameter exists.
$args->exists('param1');

In this example, the exists method checks whether a value exists for the param1 input parameter.

  • If the param1 parameter exists, the method returns true ( 1 ).
  • If the param1 parameter does not exist, the method returns false ( 0 ).
Note:

This method returns true if the parameter exists with a null or blank value.


$args->get()

This method retrieves one or more named parameters. We recommend that you use this method to assign values from optional input parameters.

# Assign param1's value to $arg1 and param2's value to $arg2.
# The param1 and param2 input parameters are optional.
my($arg1, $arg2) = $args->get('param1', 'param2');

This example assigns the param1 parameter's value to the $arg1 variable, and the param2 parameter's value to the $arg2 variable.

Note:

This method does not return runtime errors if the method attempts to assign a value from a nonexistent parameter.

  • For this reason, we recommend that you do not use this method with required parameters.
  • To check whether a parameter exists and then return the value or an error message, use the get_required() method.

$args->get_required()

This method checks whether a named parameter exists.

  • If the parameter exists, the method returns that parameter and its value.
  • If it does not exist, the method returns a predetermined error message.

We recommend that you use this method to assign values from required input parameters that could have a blank value.

# Assign param1's value to $variable.
# Returns an error if param1 does not exist.
# No error if param1's value is blank.
my ($variable) = $args->get_required('param1');

This example uses the get_required method to check whether the param1 parameter exists, and then assigns the parameter and its value to the $variable variable.

Note:

This method does not return an error if the parameter exists with a null or blank value.


$args->getlengthrequired()

This method checks whether a named parameter exists, and ensures that it is not a blank or null value.

  • If the parameter exists and has a value, the method returns that parameter and its value.
  • If it does not exist, has a blank value, or has a null value, the method returns a predetermined error message.

We recommend that you use this method to assign values from required input parameters that must not be empty.

# Assign param1's value to $variable.
# Returns an error if param1 does not have a value or is empty.
my ($variable) = $args->get_length_required('param1');

This example uses the get_length_required method to check whether the param1 parameter exists and has a valid value, and then assigns the parameter and its value to the $variable variable.

$args->add()

This method adds a key=value pair to the currently available named parameters. Use this method, for example, to introduce additional parameters from another subroutine.

$args->add('parameter_name','value');

In this example, the add method adds the parameter_name parameter, and assigns it a value of value.

$args->keys()

This method retrieves all of the current named parameters. Use this method to assign all of the named input parameters to an array, without the need to explicitly name each parameter.

my $value = $args->keys();

In this example, the keys method assigns all of the available named parameters and their values to the $value variable.

The cPanel Result objects

UAPI modules use the Cpanel::Result object to return messages and data. When you write a custom UAPI module, you must use this object for your functions to operate correctly.

For more information about methods in Perl, read perl.org's perlobj documentation.

Required $result declaration

Before you can use Cpanel::Result methods, you must declare the $result variable, as in the following example:

sub custom_function {
    my ( $args, $result ) = @_;
}

This example declares the $args and $result variables, and assigns values from the input parameters that the function received.

Important:

We strongly recommend that you begin all custom functions with the my ( $args, $result ) = @_; declaration. Functions that do not perform this action will experience errors.


Note:

If your return data contains any strings with Unicode characters that are binary encoded, and that display on a cPanel interface, you will receive a Wide Character warning. To resolve this, use the following code to encode your strings:

use Encode qw(encode);
$result->data( encode( 'utf-8', $successful_data ) );

For more information about the Cpanel::Args object, read the Cpanel::Args Object documentation above.

Methods

The Cpanel::Result object includes methods that you can use to return messages and data through UAPI.

$result->data()

This method stores data to include in the function's return data. Use this method to return the data hash for custom functions.

You can use the data() method to store individual values. However, we recommend that you instead use this method to store hashes of named parameters.

$result->data(@array_of_data);

In this example, the data method stores an array of function data. This data will appear in the data hash in the function's metadata.

Important:

Do not use this method more than once in each function. If a function uses the data() method a second time, it will overwrite all of the data that it previously stored.


$result->error()

This method stores an error message to include in the function's return data. Use this method to return error messages in custom functions.

If you call this method multiple times in the same function, it appends the new error messages to the list that it previously stored.

$result->error('This is an error message about the function.');

In this example, the error method stores an error message. This message will appear in the errors hash in the function's metadata.

Warning:
  • This method attempts to localize any message that a function passes to it.
  • For this reason, do not attempt to interpolate data into a string that you pass to this method.
  • The strings that you use with this method must be exact string literals.
  • To include interpolated data in an error message, use the raw_error() method.

$result->raw_error()

This method stores an error message to include in the function's return data. Use this method to return error messages in custom functions.

If you call this method multiple times in the same function, it appends the new error messages to the list that it previously stored.

$result->raw_error('This is an error message about the [_1].', '$function');

In this example, the raw_error method stores an error message. This message will appear in the errors hash in the function's metadata.

Note:

This method does not attempt to localize strings, and therefore is safe to use with interpolated data.


$result->message()

This method stores a message to include in the function's return data. Use this method to return messages of success, or additional function information.

If you call this method multiple times in the same function, it appends the new messages to the list that it previously stored.

$result->message('This is a message of success about the function.');

In this example, the message method stores a success message. This message will appear in the messages hash in the function's metadata.

Warning:
  • This method attempts to localize any message that a function passes to it.
  • For this reason, do not attempt to interpolate data into a string that you pass to this method.
  • The strings that you use with this method must be exact string literals.
  • To include interpolated data in an error message, use the raw_message() method.

$result->raw_message()

This method stores a message to include in the function's return data. Use this method to return messages of success, or the function's metadata

If you call this method multiple times in the same function, it appends the new messages to the list that it previously stored.

$result->raw_message('This is a message of success about the function.');

In this example, the raw_message method stores a success message. This message will appear in the messages hash in the function's metadata.

Note:

This method does not attempt to localize strings, and therefore is safe to use with interpolated data.


$result->metadata()

This method stores metadata to include in the function's return data.

$result->metadata('metadata_var', '1');

This example adds the metadata_var parameter to the hash of metadata, with a value of 1. This message will appear in the metadata hash in the function's metadata.

Note:

In most instances, custom modules will not need to use this method.