2021-02-27 13:40:40 +01:00
< ? php
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// MAILGRAPH
// =========
// Script that provides a Media Type for Zabbix that will add a graph to an e-mail that is sent out
// upon an alert message.
//
// ------------------------------------------------------------------------------------------------------
// 1.00 2021/02/26 - Mark Oudsen - MVP version, ready for distribution
2021-02-27 15:40:01 +01:00
// 1.01 2021/02/27 - Mark Oudsen - Enhanced search for associated graphs to an item // bug fixes
// 1.10 2021/02/27 - Mark Oudsen - Moved all configuration outside code
2021-03-01 18:13:32 +01:00
// 1.11 2021/02/28 - Mark Oudsen - Bugfixes
2021-03-01 20:22:42 +01:00
// 1.12 2021/03/01 - Mark Oudsen - Bugfixes
// Adding mail server configuration via config.json
2021-03-01 18:36:28 +01:00
// 1.13 2021/03/01 - Mark Oudsen - Added smtp options to encrypt none,ssl,tls
2021-03-01 19:51:11 +01:00
// 1.14 2021/03/01 - Mark Oudsen - Added smtp strict certificates yes|no via config.json
2021-03-01 20:22:42 +01:00
// 1.15 2021/03/01 - Mark Oudsen - Revised relevant graph locator; allowing other item graphs if current
// item does not have a graph associated
2021-03-02 23:17:03 +01:00
// 1.16 2021/03/02 - Mark Oudsen - Found issue with graph.get not returning graphs to requested item ids
// Workaround programmed (fetch host graphs, search for certain itemids)
2021-03-03 23:26:35 +01:00
// 1.17 2021/03/02 - Mark Oudsen - Added ability to specify period of time displayed in the graph
2021-03-05 11:57:01 +01:00
// 1.18 2021/03/04 - Mark Oudsen - Added ability to specify Tags per trigger
// Shorten long "lastvalue" or "prevvalue"
// 1.19 2021/03/05 - Mark Oudsen - Added ability to pass Zabbix 'infoXXX' parameters for TWIG template
2021-03-07 22:21:38 +01:00
// 1.20 2021/03/07 - Mark Oudsen - Production level version - leaving BETA from here on ...
2021-03-09 10:21:06 +01:00
// 1.21 2021/03/09 - Mark Oudsen - Reverted graph.get code back to original code as it was not a bug but
// a wrongly typed requested (should be ARRAY, not comma separated)!
2021-03-10 19:57:42 +01:00
// 1.22 2021/03/10 - Mark Oudsen - Added ability to embed multiple periods (1-4) of the same graph
2021-03-12 15:38:46 +01:00
// 1.23 2021/03/12 - Mark Oudsen - Added graph support for 'Stacked', 'Pie' and 'Exploded'
2021-03-12 16:23:47 +01:00
// 1.24 2021/03/12 - Mark Oudsen - Added support for HTTP proxy
2021-03-17 13:03:54 +01:00
// 1.25 2021/03/16 - Mark Oudsen - Refactoring for optimized flow and relevant data retrieval
2021-03-19 12:01:41 +01:00
// 1.26 2021/03/19 - Mark Oudsen - Bugfixes after refactor (wrong itemId and incorrect eventValue)
// Suppressing Zabbix username-password in log
2021-03-20 14:06:08 +01:00
// 1.27 2021/03/19 - Mark Oudsen - Added ability to define "mailGraph.screen" tag to embed graphs from
// Added PHP informational and warnings to log for easier debug/spotting
2021-02-27 13:40:40 +01:00
// ------------------------------------------------------------------------------------------------------
//
// (C) M.J.Oudsen, mark.oudsen@puzzl.nl
// MIT License
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// MAIN SEQUENCE
// -------------
// 1) Fetch trigger, item, host, graph, event information via Zabbix API via CURL
2021-03-10 19:57:42 +01:00
// 2) Fetch Graph(s) associated to the item/trigger (if any) via Zabbix URL login via CURL
2021-02-27 13:40:40 +01:00
// 3) Build and send mail message from template using Swift/TWIG
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// CONSTANTS
2021-03-20 14:06:08 +01:00
$cVersion = 'v1.27' ;
2021-02-27 13:40:40 +01:00
$cCRLF = chr ( 10 ) . chr ( 13 );
$maskDateTime = 'Y-m-d H:i:s' ;
2021-03-20 14:06:08 +01:00
$maxGraphs = 4 ;
2021-02-27 13:40:40 +01:00
// DEBUG SETTINGS
2021-02-27 15:40:01 +01:00
// -- Should be FALSE for production level use
2021-02-27 13:40:40 +01:00
2021-03-19 12:22:01 +01:00
$cDebug = FALSE ; // Extended debug logging mode
2021-03-07 22:21:38 +01:00
$cDebugMail = FALSE ; // If TRUE, includes log in the mail message (html and plain text attachments)
$showLog = FALSE ; // Display the log - !!! only use in combination with CLI mode !!!
2021-02-27 13:40:40 +01:00
// INCLUDE REQUIRED LIBRARIES (Composer)
2021-02-27 15:40:01 +01:00
// (configure at same location as the script is running or load in your own central library)
2021-02-27 13:40:40 +01:00
// -- swiftmailer/swiftmailer https://swiftmailer.symfony.com/docs/introduction.html
// -- twig/twig https://twig.symfony.com/doc/3.x/templates.html
2021-03-01 19:51:11 +01:00
// Change only required if you decide to use a local/central library, otherwise leave as is
2021-02-27 15:40:01 +01:00
include ( getcwd () . '/vendor/autoload.php' );
2021-02-27 13:40:40 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fetch the HTML source of the given URL
// --- Redirects will be honored
// --- Enforces use of IPv4
// --- Caller must verify if the return string is JSON or ERROR
function postJSON ( $url , $data )
{
global $cCRLF ;
global $cVersion ;
global $cDebug ;
2021-03-12 16:23:47 +01:00
global $HTTPProxy ;
2021-02-27 13:40:40 +01:00
// Initialize Curl instance
_log ( '% postJSON: ' . $url );
2021-03-19 12:01:41 +01:00
if ( $cDebug ) { _log ( '> POST data: ' . json_encode ( maskOutputContent ( $data ))); }
2021-02-27 13:40:40 +01:00
$ch = curl_init ();
// Set options
curl_setopt ( $ch , CURLOPT_USERAGENT , 'Zabbix-mailGraph - ' . $cVersion );
2021-03-12 16:23:47 +01:00
if (( isset ( $HTTPProxy )) && ( $HTTPProxy != '' ))
{
_log ( '% Using proxy: ' . $HTTPProxy );
curl_setopt ( $ch , CURLOPT_PROXY , $HTTPProxy );
}
2021-02-27 13:40:40 +01:00
curl_setopt ( $ch , CURLOPT_IPRESOLVE , CURL_IPRESOLVE_V4 );
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , TRUE );
curl_setopt ( $ch , CURLOPT_CONNECTTIMEOUT , 20 );
curl_setopt ( $ch , CURLOPT_URL , $url );
curl_setopt ( $ch , CURLOPT_HTTPHEADER , array ( 'Content-Type:application/json' ));
curl_setopt ( $ch , CURLOPT_POST , TRUE );
2021-03-07 22:21:38 +01:00
curl_setopt ( $ch , CURLOPT_POSTFIELDS ,
json_encode ( $data , JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK ));
2021-02-27 13:40:40 +01:00
// Execute Curl
$data = curl_exec ( $ch );
if ( $data === FALSE )
{
_log ( '! Failed: ' . curl_error ( $ch ));
$data = 'An error occurred while retreiving the requested page.' . $cCRLF ;
$data .= 'Requested page = ' . $url . $cCRLF ;
$data .= 'Error = ' . curl_error ( $ch ) . $cCRLF ;
}
2021-03-07 22:21:38 +01:00
else
{
2021-02-27 13:40:40 +01:00
_log ( '> Received ' . strlen ( $data ) . ' bytes' );
2021-03-07 22:21:38 +01:00
$data = json_decode ( $data , TRUE );
}
2021-02-27 13:40:40 +01:00
// Close Curl
curl_close ( $ch );
// Return received response
return $data ;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fetch the given Zabbix image
// --- Store with unique name
// --- Pass filename back to caller
2021-03-03 23:26:35 +01:00
function GraphImageById ( $graphid , $width = 400 , $height = 100 , $graphType = 0 , $showLegend = 0 , $period = '48h' )
2021-02-27 13:40:40 +01:00
{
global $z_server ;
global $z_user ;
global $z_pass ;
global $z_tmp_cookies ;
global $z_images_path ;
global $z_url_api ;
global $cVersion ;
2021-02-27 17:17:54 +01:00
global $cCRLF ;
2021-03-12 16:23:47 +01:00
global $HTTPProxy ;
2021-02-27 13:40:40 +01:00
// Unique names
$thisTime = time ();
// Relative web calls
$z_url_index = $z_server . " index.php " ;
2021-03-12 15:38:46 +01:00
switch ( $graphType )
{
// 0: Normal
// 1: Stacked
2021-03-12 15:41:48 +01:00
case 0 :
case 1 :
2021-03-12 15:38:46 +01:00
$z_url_graph = $z_server . " chart2.php " ;
break ;
// 2: Pie
// 3: Exploded
2021-03-12 15:41:48 +01:00
case 2 :
case 3 :
2021-03-12 15:38:46 +01:00
$z_url_graph = $z_server . " chart6.php " ;
break ;
2021-03-12 16:23:47 +01:00
default :
// Catch all ...
_log ( '% Graph type #' . $graphType . ' unknown; forcing "Normal"' );
$z_url_graph = $z_server . " chart2.php " ;
2021-03-12 15:38:46 +01:00
}
2021-03-02 23:17:03 +01:00
$z_url_fetch = $z_url_graph . " ?graphid= " . $graphid . " &width= " . $width . " &height= " . $height .
2021-03-03 23:26:35 +01:00
" &graphtype= " . $graphType . " &legend= " . $showLegend . " &profileIdx=web.graphs.filter " .
" &from=now- " . $period . " &to=now " ;
2021-02-27 13:40:40 +01:00
// Prepare POST login
$z_login_data = array ( 'name' => $z_user , 'password' => $z_pass , 'enter' => " Sign in " );
// Cookie and image names
$filename_cookie = $z_tmp_cookies . " zabbix_cookie_ " . $graphid . " . " . $thisTime . " .txt " ;
2021-03-10 19:57:42 +01:00
$filename = " zabbix_graph_ " . $graphid . " . " . $thisTime . " - " . $period . " .png " ;
2021-02-27 13:40:40 +01:00
$image_name = $z_images_path . $filename ;
// Configure CURL
_log ( '% GraphImageById: ' . $z_url_fetch );
$ch = curl_init ();
curl_setopt ( $ch , CURLOPT_URL , $z_url_index );
curl_setopt ( $ch , CURLOPT_HEADER , false );
curl_setopt ( $ch , CURLOPT_USERAGENT , 'Zabbix-mailGraph - ' . $cVersion );
2021-03-12 16:23:47 +01:00
if (( isset ( $HTTPProxy )) && ( $HTTPProxy != '' ))
{
_log ( '% Using proxy: ' . $HTTPProxy );
curl_setopt ( $ch , CURLOPT_PROXY , $HTTPProxy );
}
2021-02-27 13:40:40 +01:00
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , true );
curl_setopt ( $ch , CURLOPT_BINARYTRANSFER , true );
curl_setopt ( $ch , CURLOPT_SSL_VERIFYPEER , false );
curl_setopt ( $ch , CURLOPT_POST , true );
curl_setopt ( $ch , CURLOPT_POSTFIELDS , $z_login_data );
curl_setopt ( $ch , CURLOPT_COOKIEJAR , $filename_cookie );
curl_setopt ( $ch , CURLOPT_COOKIEFILE , $filename_cookie );
// Login to Zabbix
2021-02-27 17:17:54 +01:00
$login = curl_exec ( $ch );
if ( $login != '' )
{
echo 'Error logging in to Zabbix!' . $cCRLF ;
die ;
}
2021-02-27 13:40:40 +01:00
// Get the graph
curl_setopt ( $ch , CURLOPT_URL , $z_url_fetch );
$output = curl_exec ( $ch );
2021-02-27 17:17:54 +01:00
2021-02-27 13:40:40 +01:00
curl_close ( $ch );
// Delete cookie
unlink ( $filename_cookie );
// Write file
$fp = fopen ( $image_name , 'w' );
fwrite ( $fp , $output );
fclose ( $fp );
// Return filename
_log ( '> Received ' . strlen ( $output ) . ' bytes' );
_log ( '> Saved to ' . $z_images_path . $filename );
return ( $filename );
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Log information
$logging = array ();
function _log ( $information )
{
global $logging ;
global $maskDateTime ;
global $showLog ;
global $cCRLF ;
$logString = date ( $maskDateTime ) . ' : ' . $information ;
$logging [] = $logString ;
if ( $showLog ) { echo $logString . $cCRLF ; }
}
2021-03-20 14:06:08 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Catch PHP warnings/notices/errors
function catchPHPerrors ( $errno , $errstr , $errfile , $errline )
{
// --- Just log ...
_log ( '!! (' . $errno . ') "' . $errstr . '" at line #' . $errline . ' of "' . $errfile . '"' );
// --- We do not take care of any errors, etc.
return FALSE ;
}
set_error_handler ( " catchPHPerrors " );
2021-02-27 15:40:01 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Read configuration file
function readConfig ( $fileName )
{
global $cCRLF ;
if ( ! file_exists ( $fileName ))
{
echo 'Config file not found. (' . $fileName . ')' . $cCRLF ;
die ;
}
$content = file_get_contents ( $fileName );
$data = json_decode ( $content , TRUE );
if ( $data == NULL )
{
echo 'Invalid JSON format in config file?! (' . $fileName . ')' . $cCRLF ;
die ;
}
return ( $data );
}
2021-02-27 13:40:40 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// API request ID counter - for best practice / debug purposes only
$requestCounter = 0 ;
function nextRequestID ()
{
global $requestCounter ;
$requestCounter ++ ;
return ( $requestCounter );
}
2021-03-19 12:01:41 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Check the array for information we do not want to share in any logging
function maskOutputFields ( $info )
{
foreach ( $info as $aKey => $aValue )
{
switch ( $aKey )
{
case 'zabbix_user' :
case 'zabbix_user_pwd' :
case 'zabbix_api_user' :
case 'zabbix_api_pwd' :
$info [ $aKey ] = '<masked>' ;
break ;
}
}
return ( $info );
}
// Check the array if it contains information that should not be logged
function maskOutputContent ( $info )
{
global $config ;
foreach ( $info as $infoKey => $infoValue )
{
if ( is_array ( $infoValue )) { $info [ $infoKey ] = maskOutputContent ( $infoValue ); }
foreach ( $config as $aKey => $aValue )
{
switch ( $aKey )
{
case 'zabbix_user' :
case 'zabbix_user_pwd' :
case 'zabbix_api_user' :
case 'zabbix_api_pwd' :
if ( $aValue == $infoValue ) { $info [ $infoKey ] = '<masked>' ; };
break ;
}
}
}
return ( $info );
}
2021-02-27 13:40:40 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Initialize ///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
2021-03-03 23:26:35 +01:00
// --- CONFIG DATA ---
2021-02-27 15:40:01 +01:00
// [CONFIGURE] Change only when you want to place your config file somewhere else ...
$config = readConfig ( getcwd () . '/config/config.json' );
2021-03-19 12:01:41 +01:00
_log ( '# Configuration taken from config.json' . $cCRLF .
json_encode ( maskOutputFields ( $config ), JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK ));
2021-03-01 18:13:32 +01:00
2021-03-03 23:26:35 +01:00
// --- POST DATA ---
2021-02-27 15:40:01 +01:00
// Read POST data
2021-02-27 13:40:40 +01:00
$problemJSON = file_get_contents ( 'php://input' );
$problemData = json_decode ( $problemJSON , TRUE );
2021-03-03 23:26:35 +01:00
// --- CLI DATA ---
2021-03-12 16:23:47 +01:00
$HTTPProxy = '' ;
2021-02-27 15:40:01 +01:00
// Facilitate CLI based testing
2021-02-27 13:40:40 +01:00
if ( isset ( $argc ))
{
if (( $argc > 1 ) && ( $argv [ 1 ] == 'test' ))
{
2021-02-27 15:40:01 +01:00
_log ( '# Invoked from CLI' );
2021-02-27 13:40:40 +01:00
2021-02-27 15:40:01 +01:00
// Assumes that config.json file has the correct information
2021-03-03 23:26:35 +01:00
2021-03-10 19:57:42 +01:00
// MANDATORY
2021-02-27 15:40:01 +01:00
$problemData [ 'itemId' ] = $config [ 'cli_itemId' ];
$problemData [ 'eventId' ] = $config [ 'cli_eventId' ];
$problemData [ 'recipient' ] = $config [ 'cli_recipient' ];
$problemData [ 'baseURL' ] = $config [ 'cli_baseURL' ];
$problemData [ 'duration' ] = $config [ 'cli_duration' ];
2021-02-27 13:40:40 +01:00
2021-03-10 19:57:42 +01:00
// OPTIONAL
2021-03-17 13:03:54 +01:00
if ( isset ( $config [ 'cli_subject' ])) { $problemData [ 'subject' ] = $config [ 'cli_subject' ]; }
if ( isset ( $config [ 'cli_period' ])) { $problemData [ 'period' ] = $config [ 'cli_period' ]; }
2021-03-10 19:57:42 +01:00
if ( isset ( $config [ 'cli_period_header' ])) { $problemData [ 'period_header' ] = $config [ 'cli_period_header' ]; }
if ( isset ( $config [ 'cli_periods' ])) { $problemData [ 'periods' ] = $config [ 'cli_periods' ]; }
if ( isset ( $config [ 'cli_periods_headers' ])) { $problemData [ 'periods_headers' ] = $config [ 'cli_periods_headers' ]; }
if ( isset ( $config [ 'cli_debug' ])) { $problemData [ 'debug' ] = $config [ 'cli_debug' ]; }
2021-03-12 16:23:47 +01:00
if ( isset ( $config [ 'cli_proxy' ])) { $problemData [ 'HTTPProxy' ] = $config [ 'cli_proxy' ]; }
2021-03-10 19:57:42 +01:00
2021-02-27 13:40:40 +01:00
// Switch on CLI log display
$showLog = TRUE ;
}
}
2021-03-20 14:06:08 +01:00
_log ( '# Data passed to MailGraph main routine and used for processing' .
$cCRLF . json_encode ( $problemData , JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK ));
2021-03-01 18:13:32 +01:00
2021-03-03 23:26:35 +01:00
// --- CHECK AND SET P_ VARIABLES ---
2021-03-05 11:57:01 +01:00
// FROM POST OR CLI DATA
2021-03-01 18:13:32 +01:00
2021-02-27 13:40:40 +01:00
if ( ! isset ( $problemData [ 'itemId' ])) { echo " Missing ITEM ID? \n " ; die ; }
$p_itemId = intval ( $problemData [ 'itemId' ]);
if ( ! isset ( $problemData [ 'eventId' ])) { echo " Missing EVENT ID? \n " ; die ; }
$p_eventId = intval ( $problemData [ 'eventId' ]);
if ( ! isset ( $problemData [ 'recipient' ])) { echo " Missing RECIPIENT? \n " ; die ; }
$p_recipient = $problemData [ 'recipient' ];
if ( ! isset ( $problemData [ 'duration' ])) { echo " Missing DURATION? \n " ; die ; }
2021-02-28 21:31:46 +01:00
$p_duration = intval ( $problemData [ 'duration' ]);
2021-02-27 13:40:40 +01:00
if ( ! isset ( $problemData [ 'baseURL' ])) { echo " Missing URL? \n " ; die ; }
$p_URL = $problemData [ 'baseURL' ];
2021-03-02 23:17:03 +01:00
$p_subject = '{{ EVENT_SEVERITY }}: {{ EVENT_NAME|raw }}' ;
2021-02-28 21:31:46 +01:00
if ( isset ( $problemData [ 'subject' ])) { $p_subject = $problemData [ 'subject' ]; }
2021-02-27 13:40:40 +01:00
$p_graphWidth = 450 ;
if ( isset ( $problemData [ 'graphWidth' ])) { $p_graphWidth = intval ( $problemData [ 'graphWidth' ]); }
$p_graphHeight = 120 ;
if ( isset ( $problemData [ 'graphHeight' ])) { $p_graphHeight = intval ( $problemData [ 'graphHeight' ]); }
$p_showLegend = 0 ;
if ( isset ( $problemData [ 'showLegend' ])) { $p_showLegend = intval ( $problemData [ 'showLegend' ]); }
2021-03-03 23:26:35 +01:00
$p_period = '48h' ;
if ( isset ( $problemData [ 'period' ])) { $p_period = $problemData [ 'period' ]; }
2021-03-12 16:23:47 +01:00
if ( isset ( $problemData [ 'HTTPProxy' ])) { $HTTPProxy = $problemData [ 'HTTPPRoxy' ]; }
2021-03-05 11:57:01 +01:00
// DYNAMIC VARIABLES FROM ZABBIX
foreach ( $problemData as $aKey => $aValue )
{
if ( substr ( $aKey , 0 , 4 ) == 'info' ) { $mailData [ $aKey ] = $aValue ; }
}
2021-03-03 23:26:35 +01:00
// FROM CONFIG DATA
2021-03-01 18:13:32 +01:00
$p_smtp_server = 'localhost' ;
if ( isset ( $config [ 'smtp_server' ])) { $p_smtp_server = $config [ 'smtp_server' ]; }
$p_smtp_port = 25 ;
if ( isset ( $config [ 'smtp_port' ])) { $p_smtp_port = $config [ 'smtp_port' ]; }
2021-02-27 13:40:40 +01:00
2021-03-01 18:36:28 +01:00
$p_smtp_transport = 'none' ;
if (( isset ( $config [ 'smtp_transport' ])) && ( $config [ 'smtp_transport' ] == 'tls' )) { $p_smtp_transport = 'tls' ; }
if (( isset ( $config [ 'smtp_transport' ])) && ( $config [ 'smtp_transport' ] == 'ssl' )) { $p_smtp_transport = 'ssl' ; }
2021-03-01 19:51:11 +01:00
$p_smtp_strict = 'yes' ;
if (( isset ( $config [ 'smtp_strict' ])) && ( $config [ 'smtp_strict' ] == 'no' )) { $p_smtp_strict = 'no' ; }
2021-03-01 20:22:42 +01:00
$p_graph_match = 'any' ;
if (( isset ( $config [ 'graph_match' ])) && ( $config [ 'graph_match' ] == 'exact' )) { $p_graph_match = 'exact' ; }
2021-03-03 23:26:35 +01:00
// --- GLOBAL CONFIGURATION ---
2021-02-27 13:40:40 +01:00
2021-02-27 15:40:01 +01:00
// Script related settings
$z_url = $config [ 'script_baseurl' ]; // Script URL location (for relative paths to images, templates, log, tmp)
$z_url_image = $z_url . 'images/' ; // Images URL (included in plain message text)
2021-02-27 13:40:40 +01:00
// Absolute path where to store the generated images - note: script does not take care of clearing out old images!
2021-02-27 15:40:01 +01:00
$z_path = getcwd () . '/' ; // Absolute base path on the filesystem for this url
2021-03-07 22:21:38 +01:00
$z_images_path = $z_path . 'images/' ;
$z_template_path = $z_path . 'templates/' ;
$z_tmp_cookies = $z_path . 'tmp/' ;
$z_log_path = $z_path . 'log/' ;
2021-02-27 13:40:40 +01:00
// Zabbix user (requires Super Admin access rights to access image generator script)
2021-02-27 15:40:01 +01:00
$z_user = $config [ 'zabbix_user' ];
$z_pass = $config [ 'zabbix_user_pwd' ];
2021-02-27 13:40:40 +01:00
// Zabbix API user (requires Super Admin access rights)
// TODO: Check if information retreival can be done with less rigths
2021-02-27 15:40:01 +01:00
$z_api_user = $config [ 'zabbix_api_user' ];
$z_api_pass = $config [ 'zabbix_api_pwd' ];
2021-02-27 13:40:40 +01:00
// Mail sender
2021-02-27 15:40:01 +01:00
$mailFrom = array ( $config [ 'mail_from' ] => 'Zabbix Mailgraph' );
2021-02-27 13:40:40 +01:00
// Derived variables - do not change!
$z_server = $p_URL ; // Zabbix server URL from config
$z_url_api = $z_server . " api_jsonrpc.php " ; // Zabbix API URL
2021-03-03 23:26:35 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Check accessibility of paths and template files //////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
2021-02-27 13:40:40 +01:00
2021-03-03 23:26:35 +01:00
if ( ! is_writable ( $z_images_path )) { echo 'Image path inaccessible?' . $cCRLF ; die ; }
if ( ! is_writable ( $z_tmp_cookies )) { echo 'Cookies temporary path inaccessible?' . $cCRLF ; die ; }
if ( ! is_writable ( $z_log_path )) { echo 'Log path inaccessible?' . $cCRLF ; die ; }
if ( ! file_exists ( $z_template_path . 'html.template' )) { echo 'HTML template missing?' . $cCRLF ; die ; }
if ( ! file_exists ( $z_template_path . 'plain.template' )) { echo 'PLAIN template missing?' . $cCRLF ; die ; }
2021-02-27 13:40:40 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fetch information via API ////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
$mailData = array ();
2021-02-28 21:31:46 +01:00
$mailData [ 'BASE_URL' ] = $p_URL ;
$mailData [ 'SUBJECT' ] = $p_subject ;
2021-02-27 13:40:40 +01:00
2021-03-17 13:03:54 +01:00
// -------------
2021-02-27 13:40:40 +01:00
// --- LOGIN ---
2021-03-17 13:03:54 +01:00
// -------------
2021-02-27 13:40:40 +01:00
_log ( '# LOGIN to Zabbix' );
$request = array ( 'jsonrpc' => '2.0' ,
'method' => 'user.login' ,
'params' => array ( 'user' => $z_api_user ,
'password' => $z_api_pass ),
'id' => nextRequestID (),
'auth' => null );
$result = postJSON ( $z_url_api , $request );
$token = '' ;
if ( isset ( $result [ 'result' ])) { $token = $result [ 'result' ]; }
2021-02-27 15:40:01 +01:00
if ( $token == '' ) { echo 'Error logging in to Zabbix? (' . $z_url_api . ')' ; die ; }
2021-02-27 13:40:40 +01:00
_log ( '> Token = ' . $token );
2021-03-17 13:03:54 +01:00
// ------------------------------
// --- READ EVENT INFORMATION ---
// ------------------------------
_log ( '# Retreiving EVENT information' );
$request = array ( 'jsonrpc' => '2.0' ,
'method' => 'event.get' ,
'params' => array ( 'eventids' => $p_eventId ,
'output' => 'extend' ,
'selectRelatedObject' => 'extend' ,
'selectSuppressionData' => 'extend' ),
'auth' => $token ,
'id' => nextRequestID ());
$thisEvent = postJSON ( $z_url_api , $request );
_log ( '> Event data' . $cCRLF . json_encode ( $thisEvent , JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK ));
if ( ! isset ( $thisEvent [ 'result' ][ 0 ])) { echo '! No response data received?' . $cCRLF ; die ; }
$mailData [ 'EVENT_ID' ] = $thisEvent [ 'result' ][ 0 ][ 'eventid' ];
$mailData [ 'EVENT_NAME' ] = $thisEvent [ 'result' ][ 0 ][ 'name' ];
$mailData [ 'EVENT_OPDATA' ] = $thisEvent [ 'result' ][ 0 ][ 'opdata' ];
$mailData [ 'EVENT_SUPPRESSED' ] = $thisEvent [ 'result' ][ 0 ][ 'suppressed' ];
2021-03-19 12:01:41 +01:00
$mailData [ 'EVENT_VALUE' ] = $thisEvent [ 'result' ][ 0 ][ 'relatedObject' ][ 'value' ];
2021-03-17 13:03:54 +01:00
switch ( $mailData [ 'EVENT_VALUE' ])
{
case 0 : // Recovering
$mailData [ 'EVENT_SEVERITY' ] = 'Resolved' ;
$mailData [ 'EVENT_STATUS' ] = 'Recovered' ;
break ;
case 1 : // Triggered/Active
$_severity = array ( 'Not classified' , 'Information' , 'Warning' , 'Average' , 'High' , 'Disaster' );
$mailData [ 'EVENT_SEVERITY' ] = $_severity [ $thisEvent [ 'result' ][ 0 ][ 'severity' ]];
$mailData [ 'EVENT_STATUS' ] = 'Triggered/Active' ;
break ;
}
$p_triggerId = $thisEvent [ 'result' ][ 0 ][ 'relatedObject' ][ 'triggerid' ];
// ------------------------
2021-02-27 13:40:40 +01:00
// --- GET TRIGGER INFO ---
2021-03-17 13:03:54 +01:00
// ------------------------
2021-02-27 13:40:40 +01:00
_log ( '# Retrieve TRIGGER information' );
$request = array ( 'jsonrpc' => '2.0' ,
'method' => 'trigger.get' ,
'params' => array ( 'triggerids' => $p_triggerId ,
'output' => 'extend' ,
2021-03-04 14:29:35 +01:00
'selectFunctions' => 'extend' ,
'selectTags' => 'extend' ),
2021-02-27 13:40:40 +01:00
'expandComment' => 1 ,
'expandDescription' => 1 ,
'expandExpression' => 1 ,
'auth' => $token ,
'id' => nextRequestID ());
$thisTrigger = postJSON ( $z_url_api , $request );
_log ( '> Trigger data' . $cCRLF . json_encode ( $thisTrigger , JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK ));
2021-03-04 14:29:35 +01:00
if ( ! isset ( $thisTrigger [ 'result' ][ 0 ])) { echo '! No response data received?' . $cCRLF ; die ; }
2021-02-27 13:40:40 +01:00
$mailData [ 'TRIGGER_ID' ] = $thisTrigger [ 'result' ][ 0 ][ 'triggerid' ];
$mailData [ 'TRIGGER_DESCRIPTION' ] = $thisTrigger [ 'result' ][ 0 ][ 'description' ];
$mailData [ 'TRIGGER_COMMENTS' ] = $thisTrigger [ 'result' ][ 0 ][ 'comments' ];
2021-03-04 14:29:35 +01:00
// --- Custom settings?
$forceGraph = 0 ;
2021-03-20 14:06:08 +01:00
$triggerScreen = 0 ;
$triggerScreenPeriod = '' ;
$triggerScreenPeriodHeader = '' ;
2021-03-04 14:29:35 +01:00
foreach ( $thisTrigger [ 'result' ][ 0 ][ 'tags' ] as $aTag )
{
2021-03-05 11:57:01 +01:00
switch ( $aTag [ 'tag' ])
2021-03-04 14:29:35 +01:00
{
2021-03-05 11:57:01 +01:00
case 'mailGraph.period' :
2021-03-10 19:57:42 +01:00
$problemData [ 'period' ] = $aTag [ 'value' ];
_log ( '+ Graph display period override = ' . $problemData [ 'period' ]);
break ;
case 'mailGraph.period_header' :
$problemData [ 'period_header' ] = $aTag [ 'value' ];
_log ( '+ Graph display period header override = ' . $problemData [ 'period_header' ]);
break ;
case 'mailGraph.periods' :
$problemData [ 'periods' ] = $aTag [ 'value' ];
_log ( '+ Graph display periods override = ' . $problemData [ 'periods' ]);
break ;
case 'mailGraph.periods_headers' :
$problemData [ 'periods_headers' ] = $aTag [ 'value' ];
_log ( '+ Graph display periods headers override = ' . $problemData [ 'periods_headers' ]);
2021-03-05 11:57:01 +01:00
break ;
2021-03-04 14:29:35 +01:00
2021-03-05 11:57:01 +01:00
case 'mailGraph.graph' :
$forceGraph = intval ( $aTag [ 'value' ]);
_log ( '+ Graph ID to display = ' . $forceGraph );
break ;
case 'mailGraph.showLegend' :
$p_showLegend = intval ( $aTag [ 'value' ]);
_log ( '+ Graph display legend override = ' . $p_showLegend );
break ;
case 'mailGraph.graphWidth' :
$p_graphWidth = intval ( $aTag [ 'value' ]);
_log ( '+ Graph height override = ' . $$p_graphWidth );
break ;
case 'mailGraph.graphHeight' :
$p_graphHeight = intval ( $aTag [ 'value' ]);
_log ( '+ Graph height override = ' . $$p_graphHeight );
break ;
2021-03-10 19:57:42 +01:00
case 'mailGraph.debug' :
$problemData [ 'debug' ] = 1 ;
_log ( '+ Mail debug log enabled' );
break ;
2021-03-20 14:06:08 +01:00
case 'mailGraph.screen' :
$triggerScreen = intval ( $aTag [ 'value' ]);
_log ( '+ Trigger screen = ' . $triggerScreen );
break ;
case 'mailGraph.screenPeriod' :
$triggerScreenPeriod = $aTag [ 'value' ];
_log ( '+ Trigger screen period = ' . $triggerScreenPeriod );
break ;
case 'mailGraph.screenPeriodHeader' :
$triggerScreenPeriodHeader = $aTag [ 'value' ];
_log ( '+ Trigger screen header = ' . $triggerScreenPeriodHeader );
break ;
2021-03-04 14:29:35 +01:00
}
}
2021-03-17 13:03:54 +01:00
// ---------------------
2021-02-27 13:40:40 +01:00
// --- GET ITEM INFO ---
2021-03-17 13:03:54 +01:00
// ---------------------
2021-02-27 13:40:40 +01:00
_log ( '# Retrieve ITEM information' );
$request = array ( 'jsonrpc' => '2.0' ,
'method' => 'item.get' ,
2021-03-17 13:03:54 +01:00
'params' => array ( 'itemids' => $p_itemId ,
2021-02-27 13:40:40 +01:00
'output' => 'extend' ),
'auth' => $token ,
'id' => nextRequestID ());
$thisItem = postJSON ( $z_url_api , $request );
_log ( '> Item data' . $cCRLF . json_encode ( $thisItem , JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK ));
2021-03-04 14:29:35 +01:00
if ( ! isset ( $thisItem [ 'result' ][ 0 ])) { echo '! No response data received?' . $cCRLF ; die ; }
2021-02-27 13:40:40 +01:00
$mailData [ 'ITEM_ID' ] = $thisItem [ 'result' ][ 0 ][ 'itemid' ];
$mailData [ 'ITEM_KEY' ] = $thisItem [ 'result' ][ 0 ][ 'key_' ];
$mailData [ 'ITEM_NAME' ] = $thisItem [ 'result' ][ 0 ][ 'name' ];
$mailData [ 'ITEM_DESCRIPTION' ] = $thisItem [ 'result' ][ 0 ][ 'description' ];
$mailData [ 'ITEM_LASTVALUE' ] = $thisItem [ 'result' ][ 0 ][ 'lastvalue' ];
$mailData [ 'ITEM_PREVIOUSVALUE' ] = $thisItem [ 'result' ][ 0 ][ 'prevvalue' ];
// Catch elements that have a recordset definition returned as a value ...
if ( substr ( $mailData [ 'ITEM_LASTVALUE' ], 0 , 5 ) == '<?xml' ) { $mailData [ 'ITEM_LASTVALUE' ] = '[record]' ; }
if ( substr ( $mailData [ 'ITEM_PREVIOUSVALUE' ], 0 , 5 ) == '<?xml' ) { $mailData [ 'ITEM_PREVIOUSTVALUE' ] = '[record]' ; }
2021-03-05 11:57:01 +01:00
// Catch long elements
if ( strlen ( $mailData [ 'ITEM_LASTVALUE' ]) > 50 ) { $mailData [ 'ITEM_LASTVALUE' ] = substr ( $mailData [ 'ITEM_LASTVALUE' ], 0 , 50 ) . ' ...' ; }
if ( strlen ( $mailData [ 'ITEM_PREVIOUSVALUE' ]) > 50 ) { $mailData [ 'ITEM_PREVIOUSVALUE' ] = substr ( $mailData [ 'ITEM_PREVIOUSVALUE' ], 0 , 50 ) . ' ...' ; }
2021-03-17 13:03:54 +01:00
// ---------------------
2021-02-27 13:40:40 +01:00
// --- GET HOST INFO ---
2021-03-17 13:03:54 +01:00
// ---------------------
2021-02-27 13:40:40 +01:00
2021-02-28 21:31:46 +01:00
_log ( '# Retrieve HOST information' );
2021-02-27 13:40:40 +01:00
$hostId = $thisItem [ 'result' ][ 0 ][ 'hostid' ];
$request = array ( 'jsonrpc' => '2.0' ,
'method' => 'host.get' ,
'params' => array ( 'hostids' => $hostId ,
2021-03-20 14:06:08 +01:00
'output' => 'extend' ,
'selectTags' => 'extend' ),
2021-02-27 13:40:40 +01:00
'auth' => $token ,
'id' => nextRequestID ());
$thisHost = postJSON ( $z_url_api , $request );
_log ( '> Host data' . $cCRLF . json_encode ( $thisHost , JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK ));
2021-03-04 14:29:35 +01:00
if ( ! isset ( $thisHost [ 'result' ][ 0 ])) { echo '! No response data received?' . $cCRLF ; die ; }
2021-02-27 13:40:40 +01:00
$mailData [ 'HOST_ID' ] = $thisHost [ 'result' ][ 0 ][ 'hostid' ];
$mailData [ 'HOST_NAME' ] = $thisHost [ 'result' ][ 0 ][ 'name' ];
$mailData [ 'HOST_ERROR' ] = $thisHost [ 'result' ][ 0 ][ 'error' ];
$mailData [ 'HOST_DESCRIPTION' ] = $thisHost [ 'result' ][ 0 ][ 'description' ];
2021-03-20 14:06:08 +01:00
// --- Custom settings?
$hostScreen = 0 ;
$hostScreenPeriod = '' ;
$hostScreenPeriodHeader = '' ;
foreach ( $thisHost [ 'result' ][ 0 ][ 'tags' ] as $aTag )
{
switch ( $aTag [ 'tag' ])
{
case 'mailGraph.screen' :
$hostScreen = intval ( $aTag [ 'value' ]);
_log ( '+ Host screen (from TAG) = ' . $hostScreen );
break ;
case 'mailGraph.screenPeriod' :
$hostScreenPeriod = $aTag [ 'value' ];
_log ( '+ Host screen period (from TAG) = ' . $hostScreenPeriod );
break ;
case 'mailGraph.screenPeriodHeader' :
$hostScreenPeriodHeader = $aTag [ 'value' ];
_log ( '+ Host screen period header (from TAG) = ' . $hostScreenPeriodHeader );
break ;
}
}
2021-02-28 21:31:46 +01:00
_log ( '# Retreive HOST macro information' );
$request = array ( 'jsonrpc' => '2.0' ,
'method' => 'usermacro.get' ,
'params' => array ( 'hostids' => $hostId ,
'output' => 'extend' ),
'auth' => $token ,
'id' => nextRequestID ());
$thisMacros = postJSON ( $z_url_api , $request );
_log ( '> Host macro data' . $cCRLF . json_encode ( $thisMacros , JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK ));
2021-03-20 14:06:08 +01:00
foreach ( $thisMacros [ 'result' ] as $aMacro )
{
switch ( $aMacro [ 'macro' ])
{
case 'mailGraph.screen' :
$hostScreen = intval ( $aMacro [ 'value' ]);
_log ( '+ Host screen (from MACRO) = ' . $hostScreen );
break ;
case 'mailGraph.screenPeriod' :
$hostScreenPeriod = $aMacro [ 'value' ];
_log ( '+ Host screen period (from MACRO) = ' . $hostScreenPeriod );
break ;
case 'mailGraph.screenPeriodHeader' :
$hostScreenPeriodHeader = $aMacro [ 'value' ];
_log ( '+ Host screen header (from MACRO) = ' . $hostScreenPeriodHeader );
break ;
}
}
// ------------------------------------------------------------------
// --- GET GRAPHS ASSOCIATED WITH THIS HOST AND THE TRIGGER ITEMS ---
// ------------------------------------------------------------------
2021-02-27 13:40:40 +01:00
2021-03-09 10:21:06 +01:00
_log ( '# Retrieve associated graphs to this HOST and the TRIGGER ITEMS' );
$searchItems = array ();
foreach ( $thisTrigger [ 'result' ][ 0 ][ 'functions' ] as $aFunction )
{
$searchItems [] = $aFunction [ 'itemid' ];
}
2021-02-27 13:40:40 +01:00
$keyName = $thisItem [ 'result' ][ 0 ][ 'key_' ];
$hostId = $thisItem [ 'result' ][ 0 ][ 'hostid' ];
$request = array ( 'jsonrpc' => '2.0' ,
'method' => 'graph.get' ,
2021-03-02 23:17:03 +01:00
'params' => array ( 'hostids' => $hostId ,
2021-03-09 10:21:06 +01:00
'itemids' => $searchItems ,
2021-03-02 23:17:03 +01:00
'expandName' => 1 ,
'selectGraphItems' => 'extend' ,
2021-02-27 13:40:40 +01:00
'output' => 'extend' ),
'auth' => $token ,
'id' => nextRequestID ());
2021-03-02 23:17:03 +01:00
$thisGraphs = postJSON ( $z_url_api , $request );
_log ( '> Graphs data' . $cCRLF . json_encode ( $thisGraphs , JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK ));
2021-02-27 13:40:40 +01:00
2021-03-04 14:29:35 +01:00
if ( $forceGraph > 0 )
{
2021-03-17 13:03:54 +01:00
// --------------------------------------------
2021-03-04 14:29:35 +01:00
// --- GET GRAPH ASSOCIATED WITH FORCEGRAPH ---
2021-03-17 13:03:54 +01:00
// --------------------------------------------
_log ( '# Retrieving FORCED graph information' );
2021-03-04 14:29:35 +01:00
$request = array ( 'jsonrpc' => '2.0' ,
'method' => 'graph.get' ,
'params' => array ( 'graphids' => $forceGraph ,
'expandName' => 1 ,
'output' => 'extend' ),
'auth' => $token ,
'id' => nextRequestID ());
$forceGraphInfo = postJSON ( $z_url_api , $request );
2021-03-20 14:06:08 +01:00
_log ( '> Forced graph data' . $cCRLF .
json_encode ( $forceGraphInfo , JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK ));
2021-03-04 14:29:35 +01:00
2021-03-09 10:21:06 +01:00
if ( ! isset ( $forceGraphInfo [ 'result' ][ 0 ]))
{
_log ( '! No data received for graph #' . $forceGraph . '; discarding forced graph information' );
$forceGraph = 0 ;
}
2021-03-04 14:29:35 +01:00
}
2021-03-17 13:03:54 +01:00
// --------------------------------------------------------
2021-03-02 23:17:03 +01:00
// --- FIND MATCHING GRAPH ITEMS WITH OUR TRIGGER ITEMS ---
2021-03-17 13:03:54 +01:00
// --------------------------------------------------------
2021-02-27 13:40:40 +01:00
2021-03-02 23:17:03 +01:00
_log ( '# Matching retreived graph information with our trigger items' );
2021-02-27 13:40:40 +01:00
2021-03-17 13:03:54 +01:00
// --- Look for graphs across all functions inside the item
2021-03-09 10:21:06 +01:00
2021-03-02 23:17:03 +01:00
$itemIds = array ();
2021-02-27 13:40:40 +01:00
2021-03-02 23:17:03 +01:00
foreach ( $thisTrigger [ 'result' ][ 0 ][ 'functions' ] as $aFunction )
2021-02-27 13:40:40 +01:00
{
2021-03-02 23:17:03 +01:00
$didFind = FALSE ;
2021-02-27 13:40:40 +01:00
2021-03-02 23:17:03 +01:00
foreach ( $itemIds as $anItem )
{
if ( $anItem == $aFunction [ 'itemid' ]) { $didFind = TRUE ; break ; }
}
if ( ! $didFind ) { $itemIds [] = $aFunction [ 'itemid' ]; }
}
$matchedGraphs = array ();
$otherGraphs = array ();
2021-02-27 13:40:40 +01:00
2021-03-02 23:17:03 +01:00
foreach ( $thisGraphs [ 'result' ] as $aGraph )
{
foreach ( $aGraph [ 'gitems' ] as $aGraphItem )
2021-02-27 13:40:40 +01:00
{
2021-03-02 23:17:03 +01:00
foreach ( $itemIds as $anItemId )
2021-02-27 13:40:40 +01:00
{
2021-03-02 23:17:03 +01:00
if ( $aGraphItem [ 'itemid' ] == $anItemId )
{
2021-03-19 12:01:41 +01:00
if ( $anItemId == $p_itemId )
2021-03-02 23:17:03 +01:00
{
_log ( '+ Graph #' . $aGraphItem [ 'graphid' ] . ' full match found (item #' . $aGraphItem [ 'itemid' ] . ')' );
$matchedGraphs [] = $aGraph ;
}
else
{
$otherGraphs [] = $aGraph ;
_log ( '~ Graph #' . $aGraphItem [ 'graphid' ] . ' partial match found (item #' . $aGraphItem [ 'itemid' ] . ')' );
}
}
2021-02-27 13:40:40 +01:00
}
}
}
2021-03-02 23:17:03 +01:00
_log ( '> Graphs found (matching/partial) = ' . sizeof ( $matchedGraphs ) . ' / ' . sizeof ( $otherGraphs ));
2021-02-27 13:40:40 +01:00
2021-03-20 14:06:08 +01:00
// ---------------------------------------------------------------------------
// --- FIND MATCHING GRAPH ITEMS WITH TRIGGER AND/OR HOST SCREEN REFERENCE ---
// ---------------------------------------------------------------------------
function _sort ( $a , $b )
{
if ( $a [ 'screen' ][ 'y' ] > $b [ 'screen' ][ 'y' ]) { return ( 1 ); }
if ( $a [ 'screen' ][ 'y' ] < $b [ 'screen' ][ 'y' ]) { return ( - 1 ); }
if ( $a [ 'screen' ][ 'x' ] > $b [ 'screen' ][ 'x' ]) { return ( 1 ); }
if ( $a [ 'screen' ][ 'x' ] < $b [ 'screen' ][ 'x' ]) { return ( - 1 ); }
return ( 0 );
}
function fetchGraphsFromScreen ( $screenId )
{
global $token ;
global $z_url_api ;
global $cCRLF ;
// --- Pick up the SCREEN ITEMS associated to the SCREEN
$request = array ( 'jsonrpc' => '2.0' ,
'method' => 'screen.get' ,
'params' => array ( 'screenids' => $screenId ,
'output' => 'extend' ,
'selectScreenItems' => 'extend' ),
'auth' => $token ,
'id' => nextRequestID ());
$screenGraphs = postJSON ( $z_url_api , $request );
_log ( '> Screen items data for screen #' . $screenId . $cCRLF . json_encode ( $screenGraphs , JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK ));
// --- Filter on specific type(s) and enrich the graph data
$result = array ();
foreach ( $screenGraphs [ 'result' ][ 0 ][ 'screenitems' ] as $anItem )
{
switch ( $anItem [ 'resourcetype' ])
{
case 0 : // Graph
$request = array ( 'jsonrpc' => '2.0' ,
'method' => 'graph.get' ,
'params' => array ( 'graphids' => $anItem [ 'resourceid' ],
'expandName' => 1 ,
'output' => 'extend' ),
'auth' => $token ,
'id' => nextRequestID ());
$screenGraph = postJSON ( $z_url_api , $request );
_log ( '+ Graph data for screen item #' . $anItem [ 'screenitemid' ] . $cCRLF .
json_encode ( $screenGraph , JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK ));
$result [] = array ( 'screen' => $anItem , 'name' => $screenGraphs [ 'result' ][ 0 ][ 'name' ], 'graph' => $screenGraph [ 'result' ][ 0 ]);
break ;
}
}
// --- Sort the result according to SCREEN x,y position
usort ( $result , " _sort " );
// --- Done
return ( $result );
}
$triggerGraphs = array ();
if ( $triggerScreen > 0 )
{
_log ( '# Fetching graph information for TRIGGER for screen #' . $hostScreen );
$triggerGraphs = fetchGraphsFromScreen ( $triggerScreen );
_log ( '> Graphs found = ' . sizeof ( $triggerGraphs ));
}
if ( $hostScreen > 0 )
{
_log ( '# Fetching graph information for HOST for screen #' . $hostScreen );
$hostGraphs = fetchGraphsFromScreen ( $hostScreen );
_log ( '> Graphs found = ' . sizeof ( $hostGraphs ));
}
2021-02-27 13:40:40 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////
2021-03-20 14:06:08 +01:00
// Fetch Graph(s) ///////////////////////////////////////////////////////////////////////////////////////
2021-02-27 13:40:40 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////
2021-03-20 14:06:08 +01:00
// Determine number of periods for the ITEM graphs
2021-03-10 19:57:42 +01:00
$p_periods = array ();
$p_periods_headers = array ();
if ( isset ( $problemData [ 'periods' ]))
{
// Multiple periods mode selected
_log ( '# Multi period graph mode selected' );
$p_periods = explode ( ',' , $problemData [ 'periods' ]);
// If invalid, replace with single graph item
if ( sizeof ( $p_periods ) == 0 ) { $p_periods [] = $p_period ; }
// --- Determine headers
if ( isset ( $problemData [ 'periods_headers' ])) { $p_periods_headers = explode ( ',' , $problemData [ 'periods_headers' ]); }
// If no headers specified, simply copy the period information
if ( sizeof ( $p_periods_headers ) == 0 ) { $p_periods_headers = $p_periods ; }
}
else
{
// Single period mode selected
$p_periods [] = $p_period ;
if ( isset ( $problemData [ 'period_header' ]))
{
$p_periods_headers [] = $problemData [ 'period_header' ];
}
else
{
$p_periods_headers [] = $p_period ;
}
}
2021-03-20 14:06:08 +01:00
// Strip off any excessive elements from the end
while ( sizeof ( $p_periods ) > $maxGraphs ) { array_pop ( $p_periods ); }
while ( sizeof ( $p_periods_headers ) > $maxGraphs ) { array_pop ( $p_periods_headers ); }
// Fetching of the ITEM graphs
2021-03-10 19:57:42 +01:00
$graphFiles = array ();
2021-02-27 13:40:40 +01:00
$graphURL = '' ;
2021-03-03 23:26:35 +01:00
// If we have any matching graph, make the embedding information available
2021-03-05 11:57:01 +01:00
if (( sizeof ( $matchedGraphs ) + sizeof ( $otherGraphs ) + $forceGraph ) > 0 )
2021-02-27 13:40:40 +01:00
{
2021-03-05 11:57:01 +01:00
if ( $forceGraph > 0 )
{
$theGraph = $forceGraphInfo ;
$theType = 'Forced' ;
}
else
2021-03-01 20:22:42 +01:00
{
2021-03-04 14:29:35 +01:00
if ( sizeof ( $matchedGraphs ) > 0 )
2021-03-01 20:22:42 +01:00
{
2021-03-05 11:57:01 +01:00
$theGraph = $matchedGraphs [ 0 ];
$theType = 'Matched' ;
2021-03-04 14:29:35 +01:00
}
else
{
2021-03-05 11:57:01 +01:00
if ( sizeof ( $otherGraphs ) > 0 )
2021-03-04 14:29:35 +01:00
{
2021-03-05 11:57:01 +01:00
$theGraph = $otherGraphs [ 0 ];
$theType = 'Other' ;
2021-03-04 14:29:35 +01:00
}
2021-03-01 20:22:42 +01:00
}
2021-03-04 14:29:35 +01:00
}
2021-03-05 11:57:01 +01:00
$mailData [ 'GRAPH_ID' ] = $theGraph [ 'graphid' ];
$mailData [ 'GRAPH_NAME' ] = $theGraph [ 'name' ];
$mailData [ 'GRAPH_MATCH' ] = $theType ;
_log ( '# Adding ' . strtoupper ( $theType ) . ' graph #' . $mailData [ 'GRAPH_ID' ]);
2021-03-10 19:57:42 +01:00
foreach ( $p_periods as $aKey => $aPeriod )
{
$graphFile = GraphImageById ( $mailData [ 'GRAPH_ID' ],
$p_graphWidth , $p_graphHeight ,
$theGraph [ 'graphtype' ],
$p_showLegend , $aPeriod );
2021-03-05 11:57:01 +01:00
2021-03-10 19:57:42 +01:00
$graphFiles [] = $graphFile ;
2021-03-20 14:06:08 +01:00
$mailData [ 'GRAPHS_I' ][ $aKey ][ 'PATH' ] = $z_images_path . $graphFile ;
$mailData [ 'GRAPHS_I' ][ $aKey ][ 'URL' ] = $z_url_image . $graphFile ;
$mailData [ 'GRAPHS_I' ][ $aKey ][ 'HEADER' ] = $p_periods_headers [ $aKey ];
2021-03-10 19:57:42 +01:00
}
2021-03-05 11:57:01 +01:00
2021-03-07 22:21:38 +01:00
$mailData [ 'GRAPH_ZABBIXLINK' ] = $z_server . 'graphs.php?form=update&graphid=' . $mailData [ 'GRAPH_ID' ];
2021-02-27 13:40:40 +01:00
}
2021-03-20 14:06:08 +01:00
// Fetch graphs associated to TRIGGER or HOST screen references obtained earlier
function addGraphs ( $varName , $info , $period , $periodHeader )
{
global $p_graphWidth ;
global $p_graphHeight ;
global $p_showLegend ;
global $z_url_image ;
global $z_images_path ;
global $z_server ;
global $mailData ;
$files = array ();
foreach ( $info as $aKey => $anItem )
{
$graphFile = GraphImageById ( $anItem [ 'graph' ][ 'graphid' ],
$p_graphWidth , $p_graphHeight ,
$anItem [ 'graph' ][ 'graphtype' ],
$p_showLegend , $period );
$mailData [ 'GRAPHS_' . $varName ][ $aKey ][ 'URL' ] = $z_url_image . $graphFile ;
$mailData [ 'GRAPHS_' . $varName ][ $aKey ][ 'PATH' ] = $z_images_path . $graphFile ;
}
$mailData [ 'GRAPHS_' . $varName . '_LINK' ] = $z_server . 'screens.php?elementid=' . $info [ 0 ][ 'screen' ][ 'screenid' ];
$mailData [ 'GRAPHS_' . $varName . '_HEADER' ] = $info [ 0 ][ 'name' ];
$mailData [ 'GRAPHS_' . $varName . '_PERIODHEADER' ] = $periodHeader ;
}
if ( sizeof ( $triggerGraphs ) > 0 )
{
if ( $triggerScreenPeriod == '' )
{
$triggerScreenPeriod = $p_periods [ 0 ];
$triggerScreenPeriodHeader = $p_periods_headers [ 0 ];
}
if ( $triggerScreenPeriodHeader == '' ) { $triggerScreenPeriodHeader = $triggerScreenPeriod ; }
addGraphs ( 'T' , $triggerGraphs , $triggerScreenPeriod , $triggerScreenPeriodHeader );
$mailData [ 'TRIGGER_SCREEN' ] = $triggerScreen ;
}
if ( sizeof ( $hostGraphs ) > 0 )
{
if ( $hostScreenPeriod == '' )
{
$hostScreenPeriod = $p_periods [ 0 ];
$hostScreenPeriodHeader = $p_periods_headers [ 0 ];
}
if ( $hostScreenPeriodHeader == '' ) { $hostScreenPeriodHeader = $hostScreenPeriod ; }
addGraphs ( 'H' , $hostGraphs , $hostScreenPeriod , $hostScreenPeriodHeader );
$mailData [ 'HOST_SCREEN' ] = $hostScreen ;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Prepare HTML LOG content /////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
2021-02-27 13:40:40 +01:00
$mailData [ 'LOG_HTML' ] = implode ( '</br/>' , $logging );
$mailData [ 'LOG_HTML' ] = str_replace ( $cCRLF , '<br/>' , $mailData [ 'LOG_HTML' ]);
$mailData [ 'LOG_HTML' ] = str_replace ( '<br/>' , '<br/>' . $cCRLF , $mailData [ 'LOG_HTML' ]);
$mailData [ 'LOG_HTML' ] = '<html lang="en"><head><meta http-equiv=Content-Type content="text/html; charset=UTF-8">' . $cCRLF .
'<body>' . $cCRLF .
$mailData [ 'LOG_HTML' ] . $cCRLF .
'</body>' . $cCRLF .
'</html>' ;
// Prepare PLAIN LOG content
$mailData [ 'LOG_PLAIN' ] = implode ( chr ( 10 ), $logging );
// Prepare others
2021-03-07 22:21:38 +01:00
$mailData [ 'TRIGGER_URL' ] = $z_server . 'triggers.php?form=update&triggerid=' . $mailData [ 'TRIGGER_ID' ];
$mailData [ 'ITEM_URL' ] = $z_server . 'items.php?form=update&hostid=' . $mailData [ 'HOST_ID' ] . '&itemid=' . $mailData [ 'ITEM_ID' ];
$mailData [ 'HOST_URL' ] = $z_server . 'hosts.php?form=update&hostid=' . $mailData [ 'HOST_ID' ];
$mailData [ 'EVENTDETAILS_URL' ] = $z_server . 'tr_events.php?triggerid=' . $mailData [ 'TRIGGER_ID' ] . '&eventid=' . $mailData [ 'EVENT_ID' ];
2021-02-27 13:40:40 +01:00
2021-02-27 22:44:23 +01:00
$mailData [ 'EVENT_DURATION' ] = $p_duration ;
2021-02-27 13:40:40 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Compose & Send Message ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////
_log ( '# Setting up mailer' );
2021-03-07 22:21:38 +01:00
// Do we need TLS or SSL?
2021-03-01 18:36:28 +01:00
if (( $p_smtp_transport == 'tls' ) || ( $p_smtp_transport == 'ssl' ))
{
$transport = ( new Swift_SmtpTransport ( $p_smtp_server , $p_smtp_port , $p_smtp_transport ));
2021-03-01 19:51:11 +01:00
if ( $p_smtp_strict == 'no' )
{
if ( $transport instanceof \Swift_Transport_EsmtpTransport )
{
$transport -> setStreamOptions ([
'ssl' => [ 'allow_self_signed' => true ,
'verify_peer' => false ,
'verify_peer_name' => false ]
]);
}
}
2021-03-01 20:22:42 +01:00
else
{
2021-03-01 19:51:11 +01:00
if ( $transport instanceof \Swift_Transport_EsmtpTransport )
{
$transport -> setStreamOptions ([
'ssl' => [ 'allow_self_signed' => false ,
'verify_peer' => true ,
'verify_peer_name' => true ]
2021-03-01 20:22:42 +01:00
]);
2021-03-01 19:51:11 +01:00
}
}
2021-03-01 18:36:28 +01:00
}
else
{
$transport = ( new Swift_SmtpTransport ( $p_smtp_server , $p_smtp_port ));
}
2021-02-27 13:40:40 +01:00
$mailer = new Swift_Mailer ( $transport );
$message = ( new Swift_Message ());
// Fetch mailer ID from this message (no Swift function available for it ...)
// --- "Message-ID: <...id...@swift.generated>"
$content = $message -> toString ();
$lines = explode ( chr ( 10 ), $content );
$firstLine = $lines [ 0 ];
$idParts = explode ( ' ' , $firstLine );
$messageId = substr ( $idParts [ 1 ], 1 , - 2 );
_log ( '# Message ID = ' . $messageId );
// Build parts for HTML and PLAIN
_log ( '# Processing templates' );
_log ( '+ ' . $z_template_path . 'html.template' );
_log ( '+ ' . $z_template_path . 'plain.template' );
$loader = new \Twig\Loader\ArrayLoader ([
'html' => file_get_contents ( $z_template_path . 'html.template' ),
'plain' => file_get_contents ( $z_template_path . 'plain.template' ),
2021-02-28 21:31:46 +01:00
'subject' => $mailData [ 'SUBJECT' ],
2021-02-27 13:40:40 +01:00
]);
$twig = new \Twig\Environment ( $loader );
2021-03-20 14:06:08 +01:00
// --- Embed the images
2021-03-10 19:57:42 +01:00
2021-03-20 14:06:08 +01:00
function embedGraphs ( $graphs , $varName , $type )
{
global $message ;
global $mailData ;
2021-03-10 19:57:42 +01:00
2021-03-20 14:06:08 +01:00
foreach ( $graphs as $aKey => $anItem )
2021-03-10 19:57:42 +01:00
{
2021-03-20 14:06:08 +01:00
$mailData [ 'GRAPHS_' . $varName ][ $aKey ][ 'CID' ] = $message -> embed ( Swift_Image :: fromPath ( $mailData [ 'GRAPHS_' . $varName ][ $aKey ][ 'PATH' ]));
_log ( '> Embedded graph image (' . $type . ') ' . $mailData [ 'GRAPHS_' . $varName ][ $aKey ][ 'PATH' ]);
2021-03-10 19:57:42 +01:00
}
2021-02-27 13:40:40 +01:00
}
2021-03-20 14:06:08 +01:00
embedGraphs ( $graphFiles , 'I' , 'ITEM' );
embedGraphs ( $triggerGraphs , 'T' , 'TRIGGER' );
embedGraphs ( $hostGraphs , 'H' , 'HOST' );
// --- Render the content
2021-02-27 13:40:40 +01:00
$bodyHTML = $twig -> render ( 'html' , $mailData );
$bodyPlain = $twig -> render ( 'plain' , $mailData );
$mailSubject = $twig -> render ( 'subject' , $mailData );
// Prepare message
2021-02-28 21:31:46 +01:00
$message -> setSubject ( $mailSubject )
2021-02-27 13:40:40 +01:00
-> setFrom ( $mailFrom )
-> setTo ( $p_recipient )
-> setBody ( $bodyHTML , 'text/html' )
-> addPart ( $bodyPlain , 'text/plain' );
2021-03-10 19:57:42 +01:00
if (( $cDebugMail ) || ( isset ( $problemData [ 'debug' ])))
2021-02-27 13:40:40 +01:00
{
_log ( '# Attaching logs to mail message' );
$attachLogHTML = new Swift_Attachment ( $mailData [ 'LOG_HTML' ], 'log.html' , 'text/html' );
$message -> attach ( $attachLogHTML );
$attachLogPlain = new Swift_Attachment ( $mailData [ 'LOG_PLAIN' ], 'log.txt' , '/text/plain' );
$message -> attach ( $attachLogPlain );
}
// Send message
$result = $mailer -> send ( $message );
2021-03-10 19:57:42 +01:00
// Return Event TAG information for Zabbix
2021-02-27 13:40:40 +01:00
2021-02-27 17:17:54 +01:00
$response = array ( 'messageId.mailGraph' => $messageId );
2021-02-27 13:40:40 +01:00
echo json_encode ( $response ) . $cCRLF ;
// Store log?
2021-03-10 19:57:42 +01:00
if (( $cDebug ) || ( isset ( $problemData [ 'debug' ])))
2021-02-27 13:40:40 +01:00
{
unset ( $mailData [ 'LOG_HTML' ]);
unset ( $mailData [ 'LOG_PLAIN' ]);
2021-03-19 12:01:41 +01:00
$content = implode ( chr ( 10 ), $logging ) . $cCRLF . $cCRLF . '=== VALUES AVAILABLE FOR TWIG TEMPLATE ===' . $cCRLF . $cCRLF . json_encode ( $mailData , JSON_PRETTY_PRINT | JSON_NUMERIC_CHECK );
2021-02-27 13:40:40 +01:00
$content = str_replace ( chr ( 13 ), '' , $content );
2021-03-01 20:22:42 +01:00
$logName = 'log.' . $p_eventId . '.' . date ( 'YmdHis' ) . '.dump' ;
file_put_contents ( $z_log_path . $logName , $content );
_log ( '= Log stored to ' . $z_log_path . $logName );
2021-02-27 13:40:40 +01:00
}
2021-03-07 22:21:38 +01:00
?>