Development Guides Home >> Guide to Standardized Hooks
Guide to Standardized Hooks - Hook Action Code
You can create hook action code in a custom Perl module or as an executable script. Use hook action code to customize how cPanel & WHM functions in specific scenarios. For example, you can create a hook action Perl module that runs each time that a user creates an account.
- 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.
- Scripts may use any 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 correct location on the cPanel & WHM server:
- Install hook action code modules to your Perl environment's correct directory .
-
Save hook action scripts in the
/usr/local/cpanel/3rdparty/bin
directory. Scripts must haveroot:root
ownership and755
permissions.
-
Hook scripts execute as a separate process. Hook modules execute as part of the cPanel Server daemon (
cpsrvd
).- Hook action code in a custom Perl module can access cPanel environment variables. For steps to create a hook action code Perl module, read our Create a Standardized Hook tutorial .
- 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.
Perl module
We recommend that you use the following Perl module boilerplate for hook action code:
# 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 ) = @_;
my ($result, $message) = (0, '');
my $ok = your_action(); # Insert your action here
if ($ok) {
$result = 1; # This Boolean value is set to succeed.
$message = 'This is a success message.'; # This string is a reason for $result.
}
else {
$result = 0; # This Boolean value is set to fail.
$message = 'This is a failure message.'; # This string is a reason for $result.
}
}
1;
Package the module
# Package this module.
package MyApp::WHM;
This instructs Perl to treat all of the module's functions as part of the MyApp::WHM
module. Use the module's name as your hook action code's location when you use the /usr/local/cpanel/bin/manage_hooks
utility to register your hook.
For more information, read perldoc.perl.org's package documentation.
Set the use strict and use warnings pragmas
# Return errors if Perl experiences problems.
use strict;
use warnings;
If the file contains any code that may be unsafe, these pragmas instruct Perl to return errors.
You can omit the warnings
pragma in production code. However, 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.
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.
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 ];
}
This method embeds hook attributes in your hook action code. This helps to simplify the /usr/local/cpanel/bin/manage_hooks
hook registration process. We strongly recommend that you use this method.
For more information, read our describe()
method documentation.
Write the hook subroutine
The hook subroutine contains all of the actions that your hook will perform. When you create a hook subroutine, we recommend that you:
- Use lowercase function names.
-
Separate names that have multiple words with an underscore (
_
) character. This will help to improve readability. -
Do
not
begin functions with an underscore (
_
) character.
For more information about subroutines in Perl, read perldoc.perl.org's perlsub documentation.
Get data from @_ array
# 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 the @_
array.
When an event triggers the hook action code, the system passes in the following input parameters:
Input | Type | Description | Possible values | Example |
---|---|---|---|---|
context |
string | The hookable event and its category. | A hookable event category, two colons (: ), and the event name. |
Passwd::ChangePasswd |
data |
hash reference | The event's information. | A hash reference to a hash of key=value pairs. The system does not define the data parameter for events that do not provide data. |
key=value |
Set hook success
# Set a success and success message
my $result = 1; # This Boolean value is set to succeed.
my $message = 'This is a success message.'; # This string is a reason for $result.
...
return ($result, $message);
Set hook failure
# Set a failure and failure message
my $result = 0; # This Boolean value is set to fail.
my $message = 'This is a failure message.'; # This string is a reason for $result.
...
return ($result, $message);
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:
Input | Type | Description | Possible values | Example |
---|---|---|---|---|
result |
Boolean | Required Whether the action succeeded.
|
|
1 |
message |
string | A message of success, or an error message. To block the hook event on failure, you must set the blocking value to 1 in the describe() method. You must also include the following line in your code: die("BAILOUT $message"); If your code does not contain BAILOUT , the system will not block the event. |
|
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. The hook action code's primary return value must be a single-line print statement to STDOUT
.
Perl script
We recommend that you use the following Perl script boilerplate for hook action code:
#!/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) = @_;
my ($result, $message) = (0, '');
my $ok = your_action(); # Insert your action here
if ($ok) {
$result = 1; # This Boolean value is set to succeed.
$message = 'This is a success message.'; # This string is a reason for $result.
}
else {
$result = 0; # This Boolean value is set to fail.
$message = 'This is a failure message.'; # This string is a reason for $result.
}
}
# 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 use strict and use warnings pragmas
# Return errors if Perl experiences problems.
use strict;
use warnings;
If the file contains any code that may be unsafe, these pragmas instruct Perl to return errors.
You can omit the warnings
pragma in production code. However, 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.
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.
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 to set its value. The get_passed_data()
subroutine contains the logic to retrieve the data that the system passes via STDIN
. This subroutine then decodes the data and returns it in a useful format.
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 to set their values. The do_something()
subroutine performs the desired hook action. It also returns the 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. The 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 contains all of the actions that your hook will perform. When you create a hook subroutine, we recommend that you:
- Use lowercase function names.
-
Separate names that have multiple words with an underscore (
_
) character. This will help to improve readability. -
Do
not
begin functions with an underscore (
_
) character.
For more information about subroutines in Perl, read perldoc.perl.org's perlsub documentation.
Get data from @_ array
# Get the input data.
my ($input) = @_;
Declare the $input
variable and assign it the appropriate value from @_
array.
Set hook success
# Set a success and success message
my $result = 1; # This Boolean value is set to succeed.
my $message = 'This is a success message.'; # This string is a reason for $result.
...
return ($result, $message);
Set hook failure
# Set a failure and failure message
my $result = 0; # This Boolean value is set to fail.
my $message = 'This is a failure message.'; # This string is a reason for $result.
...
return ($result, $message);
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 the hook action code to return the following output:
Input | Type | Description | Possible values | Example |
---|---|---|---|---|
result |
Boolean | Required Whether the action succeeded.
|
|
1 |
message |
string | A message of success, or an error message. To block the hook event on failure, you must set the blocking value to 1 in the describe() method. You must also include the following line in your code: die("BAILOUT $message"); If your code does not contain BAILOUT , the system will not block the event. |
|
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 the logic to retrieve the data that the system passes via STDIN
. The subroutine then decodes and returns the data in a useful format.
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
. When an event triggers hook action code, the system passes in the following input parameters:
Input | Type | Description | Possible values | Example |
---|---|---|---|---|
context |
string | The hookable event and its category. | A hookable event category, two colons (: ), and the event name. |
Passwd::ChangePasswd |
data |
hash reference | The event's information. | A hash reference to a hash of key=value pairs. The system does not define the data parameter for events that do not provide data. |
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.
PHP script
We recommend that you use the following PHP script boilerplate for hook action code:
#!/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.
my ($result, $message) = (0, '');
my $ok = your_action(); # Insert your action here
if ($ok) {
$result = 1; # This Boolean value is set to succeed.
$message = 'This is a success message.'; # This string is a reason for $result.
}
else {
$result = 0; # This Boolean value is set to fail.
$message = 'This is a failure message.'; # This string is a reason for $result.
}
}
// 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 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
. The function then decodes and returns the data in a useful format.
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 to set their values. The do_something()
function performs the desired hook action. It also 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. The 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 contains all of the actions that your hook will perform. When you create a hook function, we recommend that you:
- Use lowercase function names.
-
Separate names that have multiple words with an underscore (
_
) character. This will help to improve readability. -
Do
not
begin functions with an underscore (
_
) character.
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 hook success
# Set a success and success message
my $result = 1; # This Boolean value is set to succeed.
my $message = 'This is a success message.'; # This string is a reason for $result.
...
return ($result, $message);
Set hook failure
# Set a failure and failure message
my $result = 0; # This Boolean value is set to fail.
my $message = 'This is a failure message.'; # This string is a reason for $result.
...
return ($result, $message);
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 the hook action code to return the following output:
Input | Type | Description | Possible values | Example |
---|---|---|---|---|
result |
Boolean | Required Whether the action succeeded.
|
|
1 |
message |
string | A message of success, or an error message. To block the hook event on failure, you must set the blocking 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. |
|
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
. This function then decodes the data and returns it in a useful format.
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.
When an event triggers the hook action code, the system passes in the following input parameters:
Input | Type | Description | Possible values | Example |
---|---|---|---|---|
context |
string | The hookable event and its category. | A hookable event category, two colons (: ), and the event name. |
Passwd::ChangePasswd |
data |
hash reference | The event's information. | A hash reference to a hash of key=value pairs. The system does not define the data parameter for events that do not provide data. |
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.