Child pages
  • Guide to Standardized Hooks - Hook Action Code
Skip to end of metadata
Go to start of metadata

Introduction


You can create hook action code in a custom Perl module or as an executable script.

 Scripts may use any scripting language that the Linux shell can execute. 


  • Hook action code file and subroutine names are arbitrary. However, the system references these names later, when you register your code.
  • Make certain that you save hook action code in the appropriate location on the cPanel & WHM server:
  • Hook scripts execute as a separate process, while hook modules execute as part of the cPanel Server daemon (cpsrvd).
    • Hook action code in custom Perl module can access cPanel environment variables.
    • Hook action code as a script cannot access cPanel environment variables.
    • For more information about cPanel environment variables, read our Guide to cPanel Variables documentation.

Note:

For detailed steps to create a hook action code Perl module, read our Create a Standardized Hook tutorial. 

Basic usage

Note:

Click a tab below to view example code and explanations for that type of hook action code.

We recommend that you use the following boilerplate for hook action code Perl modules:

# Package this module.
package MyApp::WHM;
  
# Return errors if Perl experiences problems.
use strict;
use warnings; 
    
# Properly decode JSON.
use JSON;
  
# Embed hook attributes alongside the action code.
sub describe {
    my $my_add = {
        'category' => 'Whostmgr',
        'event'    => 'Accounts::Create',
        'stage'    => 'post',
        'hook'     => 'MyApp::WHM::add',
        'exectype' => 'module',
    };
 
    return [ $my_add ];
}
 
sub add {
    # Get the data that the system passes to the hook.
    my ( $context, $data ) = @_;                
 
    # Set success and failure messages.
    my $result  = 0;                             # This boolean value is set to fail.    
    my $message = 'This is an error message.';   # This string is a reason for $result.
    
    # Insert your actions here.
 
    # Return the hook's result and message.
    return $result, $message;
}
 
1;

Package the module.

# Package this module.
package MyApp::WHM;

This declaration instructs Perl to treat all of the module's functions as part of the MyApp::WHM module.

Set the strict pragma and use warnings.

# Return errors if Perl experiences problems.
use strict;
use warnings;

These declarations instruct Perl to return errors if the file contains potentially-unsafe code.

Note:

You can omit the warnings declaration in production code, but we strongly recommend that you use it during development. 

Properly decode JSON.

# Properly decode JSON.
use JSON;

The JSON module properly encodes and decodes JSON.

Important:

Hook action code must read the entire @_ stream until end of line (EOL), and must treat it as a JSON-encoded data structure. 

Use the describe() method to embed hook attributes.

# Embed hook attributes alongside the action code.
sub describe {
    my $my_add = {
        'category' => 'Whostmgr',
        'event'    => 'Accounts::Create',
        'stage'    => 'post',
        'hook'     => 'MyApp::WHM::add',
        'exectype' => 'module',
    };
  
    return [ $my_add ];
}

The describe() method embeds hook attributes in your hook action code.

  • We strongly recommend that you use this method, because it drastically simplifies the manage_hooks hook registration process.
  • For more information, read our The describe() Method documentation.

Write the hook subroutine.

The hook subroutine should contain all of the actions that your hook will perform.

  • We recommend that you use lowercase function names.
  • If your function name includes multiple words, separate each word with an underscore (_) for readability. 
  • Do not begin functions with an underscore (_).
  • For more information about subroutines in Perl, read perldoc.perl.org's perlsub documentation.

Get data from @_

    # Get the data that the system passes to the hook.
    my ( $context, $data ) = @_; 

Declare the  $context and $data variables and assign them the appropriate values from  @_

Remember:

Hook action code that exists in a script (not a module) must read two full lines from the STDIN stream until end of line (EOL), and it must treat these lines as JSON-encoded data structures. After the system decodes the JSON string, the native data structure is a hash.

 Whenever an event triggers hook action code, the system passes in the following input parameters:

InputTypeDescriptionPossible valuesExample
contextstringThe hookable event and its category.A hookable event category, two colons (:), and the event name.Passwd::ChangePasswd
datahash referenceThe event's information.

A hash reference to a hash of key=value pairs.

Note:

Some events do not provide data. For these events, the data parameter is undefined. 

key=value

Set success and failure messages.

    # Set success and failure messages.
    my $result  = 0;                             # This boolean value is set to fail.   
    my $message = 'This is an error message.';   # This string is a reason for $result. 

Declare the  $result and $message variables and assign them values. You can manipulate these values in your custom actions, to return helpful output.

We recommend that you write hook action code to return the following output:

InputTypeDescriptionPossible valuesExample
resultboolean

Required

Whether the action succeeded.

Important:

  • 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 some circumstances, the system may misinterpret bare return values as true.
  • 1 — Success.
  • 0 — Failure.
1
messagestring

A message of success, or an error message.

Note:

To block the hook event on failure, you must set the blockable value to 1 in the describe() method and include the following line in your code:

die("BAILOUT: $message");

If your code does not contain BAILOUT, the system will not block the event.

  • A confirmation message.
  • A reason for failure.

This is an error message.

Return the hook's result.

    # Return the hook's result and message.
    return $result, $message; 

After your subroutine performs the desired actions, return the $result and $message values. Hook action code's primary return value must be a single-line print statement to STDOUT.

We recommend that you use the following boilerplate for hook action code Perl scripts:

#!/usr/local/cpanel/3rdparty/bin/perl
 
# Return errors if Perl experiences problems.
use strict;
use warnings;
 
# Use objects to handle input.
use IO::Select;
 
# Properly decode JSON.
use JSON::Syck;

# Get decoded input.
my $input = get_passed_data();

# Declare return variables and set their values.
my ( $result_result, $result_message ) = do_something($input);

# Return the return variables and exit.
print "$result_result $result_message";
exit;

# Perform the hook's action.
sub do_something {
    # Get the input data.
    my ($input) = @_;
 
    # Set success and failure messages.
    my $result  = 0;                             # This boolean value is set to fail.   
    my $message = 'This is an error message.';   # This string is a reason for $result.

    # Insert your actions here.
 
    # Return the hook result and message.
    return $result, $message;
}

# Process data from STDIN.
sub get_passed_data {
    # Declare input variables.
    my $raw_data   = '';
    my $input_data = {};
 
    # Set up an input object.
    my $selects    = IO::Select->new();
 
    # Get input from STDIN.
    $selects->add( \*STDIN );
 
    # Process the raw output, and JSON-decode.
    if ( $selects->can_read(.1) ) {
        while (<STDIN>) {
            $raw_data .= $_;
        }
        $input_data = JSON::Syck::Load($raw_data);
    }
 
    # Return the output.
    return $input_data;
} 

Set the strict pragma and use warnings.

# Return errors if Perl experiences problems.
use strict;
use warnings;

These declarations instruct Perl to return errors if the file contains potentially-unsafe code.

Note:

You can omit the warnings declaration in production code, but we strongly recommend that you use it during development. 

Properly handle input.

# Use objects to handle input.
use IO::Select;

This example uses the IO::Select module to handle input. For more information, read perldoc.perl.org's IO::Select documentation.

Properly decode JSON.

# Properly decode JSON.
use JSON::Syck;

This example uses the JSON::Syck module to properly encode and decode JSON.

Important:

Hook action code that exists in a script (not a module) must read two full lines from the STDIN  stream until end of line (EOL), and it must treat these lines as JSON-encoded data structures.

Assign decoded input to $input.

# Get decoded input.
my $input = get_passed_data(); 

Declare a variable to contain decoded input, and use the get_passed_data() subroutine (lines 39 through 60) to set its value. The get_passed_data() subroutine contains logic to retrieve the data that the system passes via STDIN, decode it, and return it in a useful format.

Remember:

Hook action code must read the entire input stream until end of line (EOL), and it must treat it as a JSON-encoded data structure. After the system decodes the JSON string, the native data structure is a hash. 

Declare return variables and set their values.

# Declare return variables and set their values.
my ( $result_result, $result_message ) = do_something($input);

Declare the $result_result and $result_message variables, and use the do_something() subroutine (lines 24 through 36) to set their values. The do_something() subroutine performs the desired hook action and returns a boolean status and a message of success or failure.

Return the hook's result and exit.

# Return the return variables and exit.
print "$result_result $result_message";
exit;

Return the $result_result and $result_message values, and then exit. Hook action code's primary return value must be a single-line print statement to STDOUT.

Write a subroutine to perform the hook's action.

The hook subroutine should contain all of the actions that your hook will perform.

  • We recommend that you use lowercase function names.
  • If your function name includes multiple words, separate each word with an underscore (_) for readability. 
  • Do not begin functions with an underscore (_).
  • For more information about subroutines in Perl, read perldoc.perl.org's perlsub documentation.

Get data from @_

    # Get the input data.
    my ($input) = @_;

Declare the $input variable and assign it the appropriate value from  @_ .

Set success and failure messages.

    # Set success and failure messages.
    my $result  = 0;                             # This boolean value is set to fail.   
    my $message = 'This is an error message.';   # This string is a reason for $result. 

Declare the $result and $message variables and assign them values. You can manipulate these values in your custom actions, to return helpful output.

We recommend that you write hook action code to return the following output:

InputTypeDescriptionPossible valuesExample
resultboolean

Required

Whether the action succeeded.

Important:

  • 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 some circumstances, the system may misinterpret bare return values as true.
  • 1 — Success.
  • 0 — Failure.
1
messagestring

A message of success, or an error message.

Note:

To block the hook event on failure, you must set the blockable value to 1 in the describe() method and include the following line in your code:

die("BAILOUT: $message");

If your code does not contain BAILOUT, the system will not block the event.

  • A confirmation message.
  • A reason for failure.

This is an error message.

Return the hook's result.

    # Return the hook's result and message.
    return $result, $message; 

After your subroutine performs the desired actions, return the $result and $message values.

Write a subroutine to retrieve and decode input.

This subroutine contains logic to retrieve the data that the system passes via STDIN , decode it, and return it in a useful format.

Remember:

Hook action code must read the entire input stream until end of line (EOL), and it must treat it as a JSON-encoded data structure. After the system decodes the JSON string, the native data structure is a hash.

Declare input variables.

    # Declare input variables.
    my $raw_data   = '';
    my $input_data = {}; 

Declare the $raw_data and $input_data variables and set their values.

Create an input object.

    # Set up an input object.
    my $selects    = IO::Select->new(); 

Declare the $selects value, and use the IO::Select module's new() method to create a new IO::Select object. For more information, read perldoc.perl.org's IO::Select documentation .

Get input from STDIN.

    # Get input from STDIN.
    $selects->add( \*STDIN ); 

Use the IO::Select module's add() method to retrieve input from STDIN.

Whenever an event triggers hook action code, the system passes in the following input parameters:

InputTypeDescriptionPossible valuesExample
contextstringThe hookable event and its category.A hookable event category, two colons (:), and the event name.Passwd::ChangePasswd
datahash referenceThe event's information.

A hash reference to a hash of key=value pairs.

Note:

Some events do not provide data. For these events, the data parameter is undefined. 

key=value

Process and JSON-decode the raw output.

    # Process the raw output, and JSON-decode.
    if ( $selects->can_read(.1) ) {
        while (<STDIN>) {
            $raw_data .= $_;
        }
        $input_data = JSON::Syck::Load($raw_data);
    }

Assign the data from STDIN to the $raw_data variable. Then, use the JSON::Syck module's Load() method to decode the raw JSON input, and assign it to the input_data variable.

Return the properly-decoded output.

    # Return the output.
    return $input_data;

Return the decoded data for use by the script's other functions.

We recommend that you use the following boilerplate for hook action code PHP scripts:

#!/usr/local/cpanel/3rdparty/bin/php -q

<?php

// Get decoded input.
$input = get_passed_data(); 

// Declare return variables and set their values.
list($result_result, $result_message) = do_something($input);

// Return the return variables.
echo "$result_result $result_message";

// Perform the hook's action, using the decoded input.
function do_something($input = array()) {
    // Insert your actions here.
 
    // Set success and failure messages.
    $result = "0";                            // This boolean value is set to fail.     
    $message = "This is an error message.";   // This string is a reason for $result.
 
    // Return the hook result and message.
    return array($result, $message);
}

// Process data from STDIN.
function get_passed_data() {
 
    // Get input from STDIN.
    $raw_data;
    $stdin_fh = fopen('php://stdin', 'r');
    if ( is_resource($stdin_fh) ) {
        stream_set_blocking($stdin_fh, 0);
        while ( ($line = fgets( $stdin_fh, 1024 )) !== false ) {
            $raw_data .= trim($line);
        }
        fclose($stdin_fh);
    }
 
    // Process and JSON-decode the raw output.
    if ($raw_data) {
        $input_data = json_decode($raw_data, true);
    } else {
        $input_data = array('context'=>array(),'data'=>array(), 'hook'=>array());
    }
 
    // Return the output.
    return $input_data;
}
?>

Assign decoded input to $input.

// Get decoded input.
$input = get_passed_data(); 

Use the get_passed_data() function (lines 27 through 38) to set the value for the $input variable. The get_passed_data() function contains logic to retrieve the data that the system passes via STDIN, decode it, and return it in a useful format.

Remember:

Hook action code must read the entire input stream until end of line (EOL), and it must treat it as a JSON-encoded data structure. After the system decodes the JSON string, the native data structure is a hash. 

Declare return variables and set their values.

// Declare return variables and set their values.
list($result_result, $result_message) = do_something($input);

Declare the $result_result and $result_message variables, and use the do_something() function (lines 15 through 24) to set their values. The do_something() function performs the desired hook action and returns a boolean status and a message of success or failure.

Return the hook's result.

// Return the return variables.
echo "$result_result $result_message";

Return the $result_result and $result_message values. Hook action code's primary return value must be a single-line print statement to STDOUT.

Write a function to perform the hook's action.

The hook function should contain all of the actions that your hook will perform.

  • We recommend that you use lowercase function names.
  • If your function name includes multiple words, separate each word with an underscore (_) for readability. 
  • Do not begin functions with an underscore (_).

Begin the function and set the $input value.

// Perform the hook's action, using the decoded input.
function do_something($input = array()) {

Begin the do_something function and assign a value to $input.

Set success and failure messages.

    // Set success and failure messages.
    $result = "0";                            // This boolean value is set to fail.    
    $message = "This is an error message.";   // This string is a reason for $result.

Assign values to the $result and $message variables. You can manipulate these values in your custom actions, to return helpful output.

We recommend that you write hook action code to return the following output:

InputTypeDescriptionPossible valuesExample
resultboolean

Required

Whether the action succeeded.

Important:

  • 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 some circumstances, the system may misinterpret bare return values as true.
  • 1 — Success.
  • 0 — Failure.
1
messagestring

A message of success, or an error message.

Note:

To block the hook event on failure, you must set the blockable value to 1 in the describe() method and include BAILOUT in the failure message. If the message does not include BAILOUT, the system will not block the event.

  • A confirmation message.
  • A reason for failure.

This is an error message.

Return the hook's result.

    // Return the hook result and message.
    return array($result, $message);

After your subroutine performs the desired actions, return the $result and $message values.

Write a function to retrieve and decode input.

This function contains logic to retrieve the data that the system passes via STDIN, decode it, and return it in a useful format.

Remember:

Hook action code must read the entire input stream until end of line (EOL), and it must treat it as a JSON-encoded data structure. After the system decodes the JSON string, the native data structure is a hash.

Get input from STDIN.

    // Get input from STDIN.
    $raw_data;
    $stdin_fh = fopen('php://stdin', 'r');
    if ( is_resource($stdin_fh) ) {
        stream_set_blocking($stdin_fh, 0);
        while ( ($line = fgets( $stdin_fh, 1024 )) !== false ) {
            $raw_data .= trim($line);
        }
        fclose($stdin_fh);
    }

Assign the values from STDIN to the $raw_data variable.

Whenever an event triggers hook action code, the system passes in the following input parameters:

InputTypeDescriptionPossible valuesExample
contextstringThe hookable event and its category.A hookable event category, two colons (:), and the event name.Passwd::ChangePasswd
datahash referenceThe event's information.

A hash reference to a hash of key=value pairs.

Note:

Some events do not provide data. For these events, the data parameter is undefined. 

key=value

Process and JSON-decode the raw output.

    // Process and JSON-decode the raw output.
    if ($raw_data) {
        $input_data = json_decode($raw_data, true);
    } else {
        $input_data = array('context'=>array(),'data'=>array(), 'hook'=>array());
    }

JSON-decode the input, and assign it to the input_data variable.

Return the properly-decoded output.

    // Return the output.
    return $input_data;

Return the decoded data for use by the script's other functions.