diff --git a/CHANGELOG.md b/CHANGELOG.md index 5024148..f6878a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ * feature: Remove archive and export functionality. Using Cacti's report log instead * feature: Add Notification Lists to Email Settings * feature: Add string based email and bcc to Email Settings +* code: Bring the entire plugin to PHPStan level 8 (0 errors) and add native parameter/return type declarations across all files +* bug: Fix the bulk "Add Data Source" action, which never added the selected items because `api_reportit_add_data_source()` was missing its `$selected_items` argument +* bug: Fix a report-template data-source lookup that passed a prepared-statement placeholder to `db_fetch_assoc()` (now uses `db_fetch_assoc_prepared()`) +* bug: Fix measurand formula-rename dependency propagation broken by a `$dependences`/`$dependencies` variable typo +* bug: Guard the undefined `show_export_wizard()` call reachable via the export action --- 2.0.0 --- diff --git a/lib/const_reports.php b/lib/const_reports.php index 7809e3b..931c825 100644 --- a/lib/const_reports.php +++ b/lib/const_reports.php @@ -46,9 +46,11 @@ */ $templates = db_fetch_assoc('SELECT * FROM plugin_reportit_templates WHERE locked = 0'); -if (!$templates) { - $templates['0'] = __('- No template available -', 'reportit'); +if (!is_array($templates) || !cacti_sizeof($templates)) { + $templates = ['0' => __('- No template available -', 'reportit')]; } else { + $tmp = []; + foreach ($templates as $key => $value) { $tmp[$templates[$key]['id']] = $templates[$key]['description']; } @@ -99,6 +101,8 @@ ]; // Timezones +global $timezones; + foreach ($timezones as $tmz => $value) { $timezone[] = $tmz; } @@ -442,7 +446,7 @@ 'owner' => [ 'friendly_name' => __('Owner', 'reportit'), 'description' => __('Change the owner of this report. Only users with the permission "view" or above can be chosen.', 'reportit'), - 'method' => (user_auth_realm(REPORTIT_USER_ADMIN, my_id()) ? 'drop_sql' : 'hidden_zero'), + 'method' => (user_auth_realm(REPORTIT_USER_ADMIN, (int) my_id()) ? 'drop_sql' : 'hidden_zero'), 'sql' => $owner_sql, 'value' => '|arg1:user_id|', ], diff --git a/lib/const_rrdlist.php b/lib/const_rrdlist.php index 88e45ef..39eca33 100644 --- a/lib/const_rrdlist.php +++ b/lib/const_rrdlist.php @@ -45,6 +45,8 @@ // $timezone - array, for dropdown menu // - contains the $keys from $timezones array. +global $timezones; + foreach ($timezones as $key => $value) { $timezone[] = $key; } diff --git a/lib/funct_calculate.php b/lib/funct_calculate.php index 6957f28..0f1ae19 100644 --- a/lib/funct_calculate.php +++ b/lib/funct_calculate.php @@ -35,7 +35,7 @@ * * @return int The count of values. */ -function f_num(&$array, &$f_cache) { +function f_num(&$array, &$f_cache): int { $f_cache['f_count'] = count($array); return $f_cache['f_count']; @@ -51,7 +51,7 @@ function f_num(&$array, &$f_cache) { * @return float The sum of values, or REPORTIT_NAN if $array is empty. */ // Sum -function f_sum(&$array, &$f_cache) { +function f_sum(&$array, &$f_cache): float { $f_cache['f_sum'] = empty($array) ? REPORTIT_NAN : array_sum($array); return $f_cache['f_sum']; @@ -68,7 +68,7 @@ function f_sum(&$array, &$f_cache) { * @return float The average value, or REPORTIT_NAN if $array is empty. */ // Average -function f_avg(&$array, &$f_cache) { +function f_avg(&$array, &$f_cache): float { $f_cache['f_avg'] = empty($array) ? REPORTIT_NAN : array_sum($array) / count($array); return $f_cache['f_avg']; @@ -85,7 +85,7 @@ function f_avg(&$array, &$f_cache) { * @return float The maximum value, or REPORTIT_NAN if $array is empty. */ // Maximum -function f_max(&$array, &$f_cache) { +function f_max(&$array, &$f_cache): float { $f_cache['f_max'] = empty($array) ? REPORTIT_NAN : max($array); return $f_cache['f_max']; @@ -102,7 +102,7 @@ function f_max(&$array, &$f_cache) { * @return float The minimum value, or REPORTIT_NAN if $array is empty. */ // Minimum -function f_min(&$array, &$f_cache) { +function f_min(&$array, &$f_cache): float { $f_cache['f_min'] = empty($array) ? REPORTIT_NAN : min($array); return $f_cache['f_min']; @@ -119,7 +119,7 @@ function f_min(&$array, &$f_cache) { * @return float The first value, or REPORTIT_NAN if $array is empty. */ // First measured value -function f_1st(&$array, &$f_cache) { +function f_1st(&$array, &$f_cache): float { $f_cache['f_1st'] = empty($array) ? REPORTIT_NAN : reset($array); return $f_cache['f_1st']; @@ -136,7 +136,7 @@ function f_1st(&$array, &$f_cache) { * @return float The last value, or REPORTIT_NAN if $array is empty. */ // Last measured value -function f_last(&$array, &$f_cache) { +function f_last(&$array, &$f_cache): float { $f_cache['f_last'] = empty($array) ? REPORTIT_NAN : end($array); return $f_cache['f_last']; @@ -154,7 +154,7 @@ function f_last(&$array, &$f_cache) { * $array is empty. */ // Gradient -function f_grd(&$array, &$f_cache) { +function f_grd(&$array, &$f_cache): float { if (empty($array)) { $f_cache['f_grd'] = REPORTIT_NAN; @@ -193,7 +193,7 @@ function f_grd(&$array, &$f_cache) { * @return float The median value, or REPORTIT_NAN if $array is empty. */ // returns the median -function f_median(&$array, &$f_cache) { +function f_median(&$array, &$f_cache): float { if ($f_cache['f_median'] === false) { if (empty($array)) { $f_cache['f_median'] = REPORTIT_NAN; @@ -226,7 +226,7 @@ function f_median(&$array, &$f_cache) { * @return float The range value, or REPORTIT_NAN if $array is empty. */ // returns the distance between the highest and lowest measured value -function f_range(&$array, &$f_cache) { +function f_range(&$array, &$f_cache): float { if ($f_cache['f_range'] === false) { $f_cache['f_range'] = empty($array) ? REPORTIT_NAN : f_max($array, $f_cache) - f_min($array, $f_cache); } @@ -246,7 +246,7 @@ function f_range(&$array, &$f_cache) { * empty. */ // returns the interquartile range -function f_iqr(&$array, &$f_cache) { +function f_iqr(&$array, &$f_cache): float { if ($f_cache['f_iqr'] === false) { if (empty($array)) { $f_cache['f_iqr'] = REPORTIT_NAN; @@ -254,7 +254,7 @@ function f_iqr(&$array, &$f_cache) { $cnt = f_num($array, $f_cache); $first_quartile = ((0.25 * $cnt) % 1 == 0) ? 0.5 * (0.25 * $cnt + (0.25 * $cnt + 1)) : intval(0.25 * $cnt + 1); $fourth_quartile = ((0.25 * $cnt) % 1 == 0) ? 0.5 * (0.75 * $cnt + (0.75 * $cnt + 1)) : intval(0.75 * $cnt + 1); - $f_cache['f_iqr'] = $array[$fourth_quartile - 1] - $array[$first_quartile - 1]; + $f_cache['f_iqr'] = $array[(int) ($fourth_quartile - 1)] - $array[(int) ($first_quartile - 1)]; } } @@ -273,7 +273,7 @@ function f_iqr(&$array, &$f_cache) { * empty. */ // returns the variance -function f_var(&$array, &$f_cache) { +function f_var(&$array, &$f_cache): float { if ($f_cache['f_var'] === false) { if (empty($array)) { $f_cache['f_var'] = REPORTIT_NAN; @@ -304,7 +304,7 @@ function f_var(&$array, &$f_cache) { * empty or its variance is NaN. */ // returns the standard deviation -function f_sd(&$array, &$f_cache) { +function f_sd(&$array, &$f_cache): float { if ($f_cache['f_sd'] === false) { if (empty($array)) { $f_cache['f_sd'] = REPORTIT_NAN; @@ -335,7 +335,7 @@ function f_sd(&$array, &$f_cache) { * if $array is empty or $value is out of range. */ // Xth percentitle -function f_xth(&$array, &$p_cache, $value) { +function f_xth(&$array, &$p_cache, $value): float { if ($value > 100 || $value <= 0) { return REPORTIT_NAN; } @@ -369,7 +369,7 @@ function f_xth(&$array, &$p_cache, $value) { * if $array is empty. */ // Sum Over Threshold -function f_sot(&$array, &$p_cache, $threshold) { +function f_sot(&$array, &$p_cache, $threshold): float { if (empty($array)) { $p_cache['f_sot'] = REPORTIT_NAN; @@ -407,7 +407,7 @@ function f_sot(&$array, &$p_cache, $threshold) { * threshold, or REPORTIT_NAN if $array is empty. */ // Duration Over Threshold -function f_dot(&$array, &$p_cache, $threshold) { +function f_dot(&$array, &$p_cache, $threshold): float { if (empty($array)) { $p_cache['f_dot'] = REPORTIT_NAN; @@ -444,7 +444,7 @@ function f_dot(&$array, &$p_cache, $threshold) { * @return float The floored value, or REPORTIT_NAN if $array is empty. */ // Get the integer value <-- should become an alias of 'f_floor' -function f_int(&$array, &$p_cache, $value) { +function f_int(&$array, &$p_cache, $value): float { $p_cache['f_int'] = empty($array) ? REPORTIT_NAN : floor($value); $p_cache['f_floor'] = $p_cache['f_int']; @@ -464,7 +464,7 @@ function f_int(&$array, &$p_cache, $value) { * @return float The floored value, or REPORTIT_NAN if $array is empty. */ // Round fractions down -function f_floor(&$array, &$p_cache, $value) { +function f_floor(&$array, &$p_cache, $value): float { $p_cache['f_floor'] = empty($array) ? REPORTIT_NAN : floor($value); $p_cache['f_int'] = $p_cache['f_floor']; @@ -484,7 +484,7 @@ function f_floor(&$array, &$p_cache, $value) { * @return float The ceiled value, or REPORTIT_NAN if $array is empty. */ // Round fractions up -function f_ceil(&$array, &$p_cache, $value) { +function f_ceil(&$array, &$p_cache, $value): float { $p_cache['f_ceil'] = empty($array) ? REPORTIT_NAN : ceil($value); return $p_cache['f_ceil']; @@ -504,7 +504,7 @@ function f_ceil(&$array, &$p_cache, $value) { * @return float The rounded value, or REPORTIT_NAN if $array is empty. */ // Get the rounded integer value <--- should become an alias of 'f_round' -function f_rnd(&$array, &$p_cache, $value) { +function f_rnd(&$array, &$p_cache, $value): float { $p_cache['f_rnd'] = empty($array) ? REPORTIT_NAN : round($value); $p_cache['f_round'] = $p_cache['f_rnd']; @@ -524,7 +524,7 @@ function f_rnd(&$array, &$p_cache, $value) { * @return float The rounded value, or REPORTIT_NAN if $array is empty. */ // Get the rounded integer value -function f_round(&$array, &$p_cache, $value) { +function f_round(&$array, &$p_cache, $value): float { $p_cache['f_round'] = empty($array) ? REPORTIT_NAN : round($value); $p_cache['f_rnd'] = $p_cache['f_round']; @@ -547,14 +547,15 @@ function f_round(&$array, &$p_cache, $value) { * empty. */ // Get the highest value of a list of given numbers -function f_high(&$array, &$p_cache) { +function f_high(&$array, &$p_cache): float { if (func_num_args() < 3 || empty($array)) { $p_cache['f_high'] = REPORTIT_NAN; return $p_cache['f_high']; } - $p_cache['f_high'] = max(array_slice(func_get_args(), 2)); + $high_values = array_slice(func_get_args(), 2); + $p_cache['f_high'] = $high_values !== [] ? max($high_values) : REPORTIT_NAN; return $p_cache['f_high']; } @@ -575,14 +576,15 @@ function f_high(&$array, &$p_cache) { * empty. */ // Get the lowest values of a list of given numbers -function f_low(&$array, &$p_cache) { +function f_low(&$array, &$p_cache): float { if (func_num_args() < 3 || empty($array)) { $p_cache['f_low'] = REPORTIT_NAN; return $p_cache['f_low']; } - $p_cache['f_low'] = min(array_slice(func_get_args(), 2)); + $low_values = array_slice(func_get_args(), 2); + $p_cache['f_low'] = $low_values !== [] ? min($low_values) : REPORTIT_NAN; return $p_cache['f_low']; } @@ -858,7 +860,7 @@ function f_isNaN(&$array, &$p_cache) { * @global string $calculate_last_formula The most recently attempted * formula string, if any. */ -function calculate_handler() { +function calculate_handler(): void { global $calculate_last_formula; if (!empty($calculate_last_formula)) { @@ -899,8 +901,8 @@ function calculate_handler() { * @param array $ds_cache Reference, the initial 'spanned metrics' * cache state. * - * @return array The computed results, keyed by data-source/RRA and - * measurand id. + * @return array|string The computed results keyed by data-source/RRA and + * measurand id, or the string 'NULL' when a query value is NaN. * * @global bool $calculate_handler_set Whether the shutdown error * handler has already been @@ -911,7 +913,7 @@ function calculate_handler() { * for calculate_handler() to * report on fatal errors. */ -function calculate(&$data, &$params, &$variables, &$df_cache, &$dm_cache, &$dr_cache, &$dp_cache, &$ds_cache) { +function calculate(&$data, &$params, &$variables, &$df_cache, &$dm_cache, &$dr_cache, &$dp_cache, &$ds_cache): array|string { $results = []; $f_cache = $df_cache; // Functions @@ -926,6 +928,8 @@ function calculate(&$data, &$params, &$variables, &$df_cache, &$dm_cache, &$dr_c $specific_variables = ['maxValue', 'maxRRDValue']; // Create a cache for every Round Robin Archive + $cache = []; + foreach ($ds_namv as $key => $ds_name) { $cache[$key] = [$f_cache, $m_cache, $p_cache]; } @@ -954,7 +958,7 @@ function calculate(&$data, &$params, &$variables, &$df_cache, &$dm_cache, &$dr_c $debug = []; // Formula - $formula = str_replace([' ', "\r\n", "\n"], '', $m); + $formula = str_replace([' ', "\r\n", "\n"], '', (string) $m); $debug[] = $formula; // transform RRA specific variables (maxValue, maxRRDValue) used in that formula @@ -974,7 +978,7 @@ function calculate(&$data, &$params, &$variables, &$df_cache, &$dm_cache, &$dr_c // Replace measurands (spanned) foreach ($s_cache as $key => $value) { $pattern = '/(^|[+|\-|*|\/|\(|\)|,| ])' . $key . '([+|\-|*|\/|\(|\)|,| ]|$)/'; - $formula = preg_replace($pattern, "\${1}$value\${2}", $formula); + $formula = (string) preg_replace($pattern, "\${1}$value\${2}", $formula); } $debug[] = $formula; @@ -991,7 +995,7 @@ function calculate(&$data, &$params, &$variables, &$df_cache, &$dm_cache, &$dr_c // Replace measurands with an existing result if we have one foreach ($cache[$i][1] as $key => $value) { $pattern = '/(^|[+|\-|*|\/|\(|\)|,| ])' . $key . '([+|\-|*|\/|\(|\)|,| ]|$)/'; - $formula = preg_replace($pattern, "\${1}$value\${2}", $formula); + $formula = (string) preg_replace($pattern, "\${1}$value\${2}", $formula); } $debug[] = $formula; @@ -1029,6 +1033,8 @@ function calculate(&$data, &$params, &$variables, &$df_cache, &$dm_cache, &$dr_c eval("\$result = $formula;"); $calculate_last_formula = ''; + /** @var mixed $result */ + if ($result === false || is_nan($result) || is_null($result)) { $result = 'NULL'; } diff --git a/lib/funct_export.php b/lib/funct_export.php index e5c618b..b8fc88f 100644 --- a/lib/funct_export.php +++ b/lib/funct_export.php @@ -31,7 +31,7 @@ * * @return void */ -function export_to_PDF(&$data) { +function export_to_PDF(&$data): void { } /** @@ -54,7 +54,7 @@ function export_to_PDF(&$data) { * scheduled/CLI context vs. an interactive * web request. */ -function export_to_CSV(&$data) { +function export_to_CSV(&$data): string { global $search, $run_scheduled; $eol = PHP_EOL; @@ -95,7 +95,7 @@ function export_to_CSV(&$data) { // plugin version $info = plugin_reportit_version(); // form the export header - $header = read_config_option('reportit_exp_header'); + $header = (string) read_config_option('reportit_exp_header'); $header = str_replace('', "$eol# Cacti: " . CACTI_VERSION, $header); $header = str_replace('', ' ReportIt: ' . $info['version'] , $header); @@ -138,6 +138,9 @@ function export_to_CSV(&$data) { } } + $ov_ids = false; + $ov_cnt = 0; + if ($datasources < 0) { // read out the 'spanned' ids [$ov_ids, $ov_cnt] = explode('-', $report_data['sp_def']); @@ -163,7 +166,7 @@ function export_to_CSV(&$data) { if ($ov_cnt > 0 && !in_array('overall', $ds_description, true)) { $ds_description[] = 'overall'; } - } elseif (in_array($measurands, $ov_ids, true)) { + } elseif (in_array($measurands, (array) $ov_ids, true)) { if ($ov_cnt > 0 && !in_array('overall', $ds_description, true)) { $ds_description = ['overall']; } @@ -247,7 +250,7 @@ function export_to_CSV(&$data) { $var = ($datasource != 'overall') ? $datasource . '__' . $id : 'spanned__' . $id; - $value = ($result[$var] == null) ? 'NA' : str_replace('.', $d_sep, (($no_formatting) ? $result[$var] : get_unit($result[$var], $rounding, $data_type, $data_precision))); + $value = ($result[$var] == null) ? 'NA' : str_replace('.', $d_sep, (string) get_unit($result[$var], $rounding, $data_type, $data_precision)); print '"' . $value . '"' . $c_sep; } @@ -257,7 +260,7 @@ function export_to_CSV(&$data) { print "$eol"; } - return ob_get_clean(); + return (string) ob_get_clean(); } /** @@ -276,7 +279,7 @@ function export_to_CSV(&$data) { * scheduled/CLI context vs. an interactive * web request. */ -function export_to_XML(&$data) { +function export_to_XML(&$data): string { global $search, $run_scheduled; $eol = PHP_EOL; @@ -296,7 +299,7 @@ function export_to_XML(&$data) { $no_formatting = 0; // form the export header - $header = read_config_option('reportit_exp_header'); + $header = (string) read_config_option('reportit_exp_header'); $header = str_replace('', "\r\nCacti: " . CACTI_VERSION, $header); $info = plugin_reportit_version(); $header = str_replace('', ' ReportIt: ' . $info['version'], $header); @@ -393,7 +396,7 @@ function export_to_XML(&$data) { $data_type = $mea[$id]['data_type']; $data_precision = $mea[$id]['data_precision']; - $value = ($value == null) ? 'NA' : (($no_formatting) ? $value : get_unit($value, $rounding, $data_type, $data_precision)); + $value = ($value == null) ? 'NA' : get_unit($value, $rounding, $data_type, $data_precision); print "<$abbr measurand=\"{$mea[$id]['abbreviation']}\" unit=\"{$mea[$id]['unit']}\">$eol"; print "$value"; print "$eol"; @@ -410,7 +413,7 @@ function export_to_XML(&$data) { print "$eol"; print "$eol$eol"; - $output = mb_convert_encoding(ob_get_clean(), 'UTF-8', 'ISO-8859-1'); + $output = mb_convert_encoding((string) ob_get_clean(), 'UTF-8', 'ISO-8859-1'); return $output; } @@ -426,7 +429,7 @@ function export_to_XML(&$data) { * yaml extension isn't available (logged as a * warning). */ -function export_to_YAML(&$data) { +function export_to_YAML(&$data): string|false { $report_data = export_to_JSON($data); if (function_exists('yaml_emit')) { @@ -454,7 +457,7 @@ function export_to_YAML(&$data) { * scheduled/CLI context vs. an interactive * web request. */ -function export_to_JSON(&$data) { +function export_to_JSON(&$data): string { global $search, $run_scheduled; $json_data = []; @@ -555,7 +558,7 @@ function export_to_JSON(&$data) { $data_type = $mea[$id]['data_type']; $data_precision = $mea[$id]['data_precision']; - $value = ($value == null) ? 'NA' : (($no_formatting) ? $value : get_unit($value, $rounding, $data_type, $data_precision)); + $value = ($value == null) ? 'NA' : get_unit($value, $rounding, $data_type, $data_precision); $json_data['data_items']['item'][$i]['results'][$datasource][$abbr]['measurand'] = $mea[$id]['abbreviation']; $json_data['data_items']['item'][$i]['results'][$datasource][$abbr]['unit'] = $mea[$id]['unit']; @@ -567,7 +570,7 @@ function export_to_JSON(&$data) { $i++; } - return json_encode($json_data, JSON_PRETTY_PRINT); + return (string) json_encode($json_data, JSON_PRETTY_PRINT); } /** @@ -582,7 +585,7 @@ function export_to_JSON(&$data) { * * @return string The rendered SpreadsheetML XML document text. */ -function export_to_SML(&$data) { +function export_to_SML(&$data): string { $eol = PHP_EOL; $sml_workbook = "', ' Cacti: ' . CACTI_VERSION, $header); $header = str_replace('', ' ReportIt: ' . $info['version'], $header); @@ -710,6 +713,9 @@ function new_worksheet(&$data, &$styles) { } } + $ov_ids = false; + $ov_cnt = 0; + if ($datasources < 0) { // read out the 'spanned' ids [$ov_ids, $ov_cnt] = explode('-', $report_data['sp_def']); @@ -734,7 +740,7 @@ function new_worksheet(&$data, &$styles) { if ($ov_cnt > 0 && !in_array('overall', $ds_description, true)) { $ds_description[] = 'overall'; } - } elseif (in_array($measurands, $ov_ids, true)) { + } elseif (in_array($measurands, (array) $ov_ids, true)) { if ($ov_cnt > 0 && !in_array('overall', $ds_description, true)) { $ds_description = ['overall']; } @@ -829,7 +835,7 @@ function new_worksheet(&$data, &$styles) { $data_precision = $report_measurands[$id]['data_precision']; $value = $result[$var]; - $value = ($value == null) ? 'NA' : (($no_formatting) ? $value : get_unit($value, $rounding, $data_type, $data_precision)); + $value = ($value == null) ? 'NA' : get_unit($value, $rounding, $data_type, $data_precision); print sml_cell($value); } } @@ -842,7 +848,7 @@ function new_worksheet(&$data, &$styles) { print "\t\t$eol"; print "\t$eol"; - return ob_get_clean(); + return (string) ob_get_clean(); } /** @@ -859,7 +865,7 @@ function new_worksheet(&$data, &$styles) { * @return string The rendered <Cell> (optionally <Row>-wrapped) XML * fragment. */ -function sml_cell($data, $row = false, $styleID = false) { +function sml_cell($data, bool $row = false, $styleID = false): string { $eol = PHP_EOL; $data_style = is_numeric($data) ? " ss:Type='Number'" : " ss:Type='String'"; diff --git a/lib/funct_html.php b/lib/funct_html.php index 05cecd9..d16ad77 100644 --- a/lib/funct_html.php +++ b/lib/funct_html.php @@ -28,8 +28,10 @@ * to the calculation formula * @param int $measurand_id contains the id of the current measurand * @param int $template_id contains the id of the template which contains the measurand + * + * @return string The rendered variable/interim-result link HTML. */ -function html_calc_syntax($measurand_id, $template_id) { +function html_calc_syntax($measurand_id, $template_id): string { global $rubrics; $rubrics[__('Variables', 'reportit')] = get_possible_variables($template_id); @@ -95,7 +97,7 @@ function html_calc_syntax($measurand_id, $template_id) { * @return array|false The form field definitions array, or false if * the template defines no variables. */ -function html_report_variables($report_id, $template_id) { +function html_report_variables(int $report_id, int $template_id): array|false { // Define some variables $array = []; $form_array_vars = []; @@ -180,8 +182,10 @@ function html_report_variables($report_id, $template_id) { * an alias for every internal data source item. * @param int $template_id - report template id, if available (new template => 0) * @param int $data_template_id - internal Cacti id of the used data template + * + * @return array The form field definitions for each data source item alias. */ -function html_template_ds_alias($template_id, $data_template_id) { +function html_template_ds_alias($template_id, $data_template_id): array { $form_array_alias = []; $data_source_items = []; @@ -262,7 +266,7 @@ function html_template_ds_alias($template_id, $data_template_id) { * * @return string The rendered <i> icon HTML. */ -function html_onoff_icon($value, $class_on, $title_on, $class_off, $title_off) { +function html_onoff_icon(string $value, string $class_on, string $title_on, string $class_off, string $title_off): string { return $value == 'on' ? "" : ""; @@ -278,7 +282,7 @@ function html_onoff_icon($value, $class_on, $title_on, $class_off, $title_off) { * * @return string The rendered lock/unlock icon HTML. */ -function html_lock_icon($value, $title_on = 'Locked', $title_off = 'Unlocked') { +function html_lock_icon(string $value, string $title_on = 'Locked', string $title_off = 'Unlocked'): string { return html_onoff_icon($value, 'fa-lock', $title_on, 'fa-lock-open', $title_off); } @@ -292,7 +296,7 @@ function html_lock_icon($value, $title_on = 'Locked', $title_off = 'Unlocked') { * * @return string The rendered check/cross icon HTML. */ -function html_check_icon($value, $title_on = 'Yes', $title_off = 'No') { +function html_check_icon(string $value, string $title_on = 'Yes', string $title_off = 'No'): string { return html_onoff_icon($value, 'fa-check deviceUp', $title_on, 'fa-times deviceDown', $title_off); } @@ -310,7 +314,7 @@ function html_check_icon($value, $title_on = 'Yes', $title_off = 'No') { * @return string The rendered icon HTML, with a '(N)' count suffix * when applicable. */ -function html_sources_icon($values, $title_on, $title_off) { +function html_sources_icon($values, string $title_on, string $title_off): string { if (is_array($values)) { $values = count($values); } @@ -318,5 +322,5 @@ function html_sources_icon($values, $title_on, $title_off) { $value_text = ($values == null ? '' : ' (' . $values . ')'); $value_on = ($values == null ? '' : 'on'); - return html_onoff_icon($values, 'fa-plus', $title_off, 'fa-wrench', $title_on) . $value_text; + return html_onoff_icon((string) $values, 'fa-plus', $title_off, 'fa-wrench', $title_on) . $value_text; } diff --git a/lib/funct_online.php b/lib/funct_online.php index 4576cb0..0bc37a0 100644 --- a/lib/funct_online.php +++ b/lib/funct_online.php @@ -28,7 +28,7 @@ * * @return int|null The current user's session id, or null if not set. */ -function my_id() { +function my_id(): int|null { return $_SESSION['sess_user_id']; } @@ -39,7 +39,7 @@ function my_id() { * @return string|null The current user's username, or null if not * found. */ -function my_name() { +function my_name(): string|null { return db_fetch_cell_prepared('SELECT username FROM user_auth WHERE id = ?', @@ -62,7 +62,7 @@ function my_name() { * * @return void */ -function my_report($report_id, $public = false) { +function my_report(int $report_id, bool $public = false): void { if (is_numeric($report_id) && $report_id != 0) { $user_id = my_id(); @@ -71,6 +71,10 @@ function my_report($report_id, $public = false) { WHERE id = ?', [$report_id]); + if (!is_array($user)) { + $user = []; + } + if ($user == false) { if (!re_admin()) { die_html_custom_error('Permission denied'); @@ -100,7 +104,7 @@ function my_report($report_id, $public = false) { * @return int|null The associated plugin_reportit_templates id, or * null if not found. */ -function my_template($report_id) { +function my_template(int $report_id): int|null { return db_fetch_cell_prepared('SELECT template_id FROM plugin_reportit_reports WHERE id = ?', @@ -118,7 +122,7 @@ function my_template($report_id) { * * @return void */ -function locked($template_id, $header = true) { +function locked(int $template_id, bool $header = true): void { $status = db_fetch_cell_prepared('SELECT locked FROM plugin_reportit_templates WHERE id = ?', @@ -137,7 +141,7 @@ function locked($template_id, $header = true) { * * @return string|null The user's username, or null if not found. */ -function other_name($userid) { +function other_name(int $userid): string|null { return db_fetch_cell_prepared('SELECT username FROM user_auth WHERE id = ?', [$userid]); } @@ -150,7 +154,7 @@ function other_name($userid) { * @return bool True if the user is view-only (or already viewing * view.php), false otherwise. */ -function only_viewer() { +function only_viewer(): bool { $id = my_id(); $report_viewer = db_fetch_cell("SELECT * @@ -178,7 +182,7 @@ function only_viewer() { * @return bool True if the user (directly or via a group) has the * realm, false otherwise. */ -function user_auth_realm($realm_id, $user_id) { +function user_auth_realm(int $realm_id, int $user_id): bool { $verified = db_fetch_cell(' SELECT user_auth.id FROM user_auth LEFT JOIN ( @@ -204,8 +208,8 @@ function user_auth_realm($realm_id, $user_id) { * @return bool True if the current user is a report owner, false * otherwise. */ -function re_owner() { - return user_auth_realm(REPORTIT_USER_OWNER, my_id()) ? true : false; +function re_owner(): bool { + return user_auth_realm(REPORTIT_USER_OWNER, (int) my_id()) ? true : false; } /** @@ -216,8 +220,8 @@ function re_owner() { * @return bool True if the current user is a ReportIt admin, false * otherwise. */ -function re_admin() { - return user_auth_realm(REPORTIT_USER_ADMIN, my_id()) ? true : false; +function re_admin(): bool { + return user_auth_realm(REPORTIT_USER_ADMIN, (int) my_id()) ? true : false; } /** @@ -235,7 +239,7 @@ function re_admin() { * * @return void */ -function session_custom_error_message($field, $custom_message, $toplevel_message = 2) { +function session_custom_error_message(string $field, string $custom_message, $toplevel_message = 2): void { $_SESSION['sess_error_fields'][$field] = $field; // Do not overwrite the first message. @@ -256,7 +260,7 @@ function session_custom_error_message($field, $custom_message, $toplevel_message * * @return void */ -function session_custom_error_display() { +function session_custom_error_display(): void { if (isset($_SESSION['sess_custom_error'])) { display_custom_error_message($_SESSION['sess_custom_error']); kill_session_var('sess_custom_error'); @@ -273,7 +277,7 @@ function session_custom_error_display() { * @return bool True if the field has a recorded error, false * otherwise. */ -function is_error_message_field($field) { +function is_error_message_field(string $field): bool { if (isset($_SESSION['sess_error_fields'][$field])) { return true; } else { @@ -291,7 +295,7 @@ function is_error_message_field($field) { * @return bool True if the template has zero measurands (eligible for * auto-lock), false otherwise. */ -function stat_autolock_template($template_id) { +function stat_autolock_template(int $template_id): bool { $count = db_fetch_cell_prepared('SELECT COUNT(*) FROM plugin_reportit_measurands WHERE template_id = ?', @@ -312,7 +316,7 @@ function stat_autolock_template($template_id) { * * @return void */ -function set_autolock_template($template_id) { +function set_autolock_template(int $template_id): void { db_execute_prepared('UPDATE plugin_reportit_templates SET locked=1 WHERE id = ?', @@ -329,7 +333,7 @@ function set_autolock_template($template_id) { * * @return void */ -function update_formulas($array) { +function update_formulas(array $array): void { foreach ($array as $key => $value) { db_execute_prepared('UPDATE plugin_reportit_measurands SET calc_formula = ? @@ -349,7 +353,7 @@ function update_formulas($array) { * @return bool True if the template was locked, false if it wasn't * eligible (has running reports). */ -function try_autolock_template($template_id) { +function try_autolock_template(int $template_id): bool { $status = db_fetch_cell_prepared('SELECT COUNT(*) FROM plugin_reportit_reports WHERE template_id = ? @@ -379,7 +383,7 @@ function try_autolock_template($template_id) { * code, used to resolve the running * version's code. */ -function check_cacti_version($hash) { +function check_cacti_version(int $hash): bool { global $hash_version_codes; if ($hash_version_codes[CACTI_VERSION] < $hash) { @@ -397,7 +401,7 @@ function check_cacti_version($hash) { * * @return void */ -function check_graph_support() { +function check_graph_support(): void { // Check required PHP extensions: GD Library and Freetype support $loaded_extensions = get_loaded_extensions(); @@ -420,13 +424,13 @@ function check_graph_support() { * * @return int The effective maximum row count to use. */ -function get_valid_max_rows() { +function get_valid_max_rows(): int { // return the default if a user defined an invalid value for maximum number of rows $session_max_rows = read_graph_config_option('reportit_max_rows'); if (is_numeric($session_max_rows) && $session_max_rows > 0) { - return $session_max_rows; + return (int) $session_max_rows; } else { - return read_default_graph_config_option('reportit_max_rows'); + return (int) read_default_graph_config_option('reportit_max_rows'); } } diff --git a/lib/funct_reports.php b/lib/funct_reports.php index dba83b7..5101d55 100644 --- a/lib/funct_reports.php +++ b/lib/funct_reports.php @@ -30,7 +30,7 @@ * * @return void */ -function api_reportit_disable_report($id) { +function api_reportit_disable_report(int $id): void { db_execute_prepared('UPDATE plugin_reportit_reports SET enabled = "" WHERE id = ?', @@ -45,7 +45,7 @@ function api_reportit_disable_report($id) { * * @return void */ -function api_reportit_enable_report($id) { +function api_reportit_enable_report(int $id): void { db_execute_prepared('UPDATE plugin_reportit_reports SET enabled = "on" WHERE id = ?', @@ -61,7 +61,8 @@ function api_reportit_enable_report($id) { * * @return void */ -function api_reportit_delete_report($id) { +function api_reportit_delete_report(int $id): void { + $counter_data_items = 0; $counter_data_items += db_fetch_cell_prepared('SELECT COUNT(*) FROM plugin_reportit_data_items WHERE report_id = ?', @@ -88,7 +89,7 @@ function api_reportit_delete_report($id) { * * @return void */ -function api_reportit_duplicate_report($id, $addition) { +function api_reportit_duplicate_report(int $id, string $addition): void { // ================= input validation ================= input_validate_input_number($id); // ==================================================== @@ -97,6 +98,10 @@ function api_reportit_duplicate_report($id, $addition) { FROM plugin_reportit_reports WHERE id = ?', [$id]); + if (!is_array($report_data)) { + $report_data = []; + } + $report_data['id'] = 0; $report_data['name'] = str_replace('', $report_data['name'], $addition); @@ -121,6 +126,10 @@ function api_reportit_duplicate_report($id, $addition) { WHERE id = ?', [$id]); + if (!is_array($report_presets)) { + $report_presets = []; + } + $report_presets['id'] = $new_id; sql_save($report_presets, 'plugin_reportit_presets', 'id', false); @@ -150,7 +159,7 @@ function api_reportit_duplicate_report($id, $addition) { * * @return void */ -function api_reportit_run_report($id) { +function api_reportit_run_report(int $id): void { $php_binary = read_config_option('path_php_binary'); // ================= input validation ================= @@ -172,7 +181,7 @@ function api_reportit_run_report($id) { * * @return void */ -function api_reportit_take_ownership($id, $user) { +function api_reportit_take_ownership(int $id, int $user): void { db_execute_prepared('UPDATE plugin_reportit_reports SET user_id = ? WHERE id = ?', [$user, $id]); } @@ -187,7 +196,7 @@ function api_reportit_take_ownership($id, $user) { * * @return void */ -function api_reportit_remove_data_sources($id, $items) { +function api_reportit_remove_data_sources(int $id, array $items): void { $rrdlist_datas = db_fetch_assoc_prepared('SELECT id FROM plugin_reportit_data_items WHERE report_id = ? @@ -210,11 +219,12 @@ function api_reportit_remove_data_sources($id, $items) { * row set if no presets exist) to each newly inserted item. Called from * the report's items tab 'add' action. * - * @param int $id The report id to add data source items to. + * @param int $id The report id to add data source items to. + * @param array $selected_items The selected RRD/graph item ids to add. * * @return void */ -function api_reportit_add_data_source($id) { +function api_reportit_add_data_source(int $id, array $selected_items): void { $enable_tmz = read_config_option('reportit_use_tmz'); $tmz = ($enable_tmz) ? "'GMT'" : "'" . date('T') . "'"; $columns = ''; @@ -227,6 +237,10 @@ function api_reportit_add_data_source($id) { WHERE id = ?', [$id]); + if (!is_array($presets)) { + $presets = []; + } + if (cacti_sizeof($presets)) { $presets['report_id'] = $id; @@ -242,7 +256,7 @@ function api_reportit_add_data_source($id) { $values .= ', ' . db_qstr($id); } - foreach ($selected_items as $rd) { + foreach ((array) $selected_items as $rd) { $rrd .= "($rd $values),"; } @@ -266,7 +280,7 @@ function api_reportit_add_data_source($id) { * * @return void */ -function api_reportit_update_data_source($id, $reference_items) { +function api_reportit_update_data_source(int $id, string $reference_items): void { $reference_items = unserialize(stripslashes($reference_items), ['allowed_classes' => false]); db_execute_prepared('UPDATE plugin_reportit_data_items diff --git a/lib/funct_runtime.php b/lib/funct_runtime.php index 90ac620..9ce251f 100644 --- a/lib/funct_runtime.php +++ b/lib/funct_runtime.php @@ -32,7 +32,7 @@ * * @return void */ -function create_result_table($report_id) { +function create_result_table(int $report_id): void { // Create the sql syntax db_execute("CREATE TABLE IF NOT EXISTS plugin_reportit_results_$report_id ( `id` int(11) NOT NULL DEFAULT 0, @@ -67,7 +67,7 @@ function create_result_table($report_id) { * resolve each measurand's * consolidation function label. */ -function get_report_definitions($report_id) { +function get_report_definitions(int $report_id): array { global $consolidation_functions; $report_definition = []; @@ -78,6 +78,10 @@ function get_report_definitions($report_id) { WHERE id = ?', [$report_id]); + if (!is_array($report)) { + $report = []; + } + // Fetch all RRD definitions $data_items = db_fetch_assoc_prepared('SELECT MAX(IF(c.field_name = "ifSpeed", c.field_value, c.field_value * 1000000)) AS `maxValue`, a.* @@ -114,6 +118,10 @@ function get_report_definitions($report_id) { WHERE id = ?', [$report['template_id']]); + if (!is_array($template)) { + $template = []; + } + // Fetch all all data source items $sql = 'SELECT data_source_name FROM plugin_reportit_data_source_items @@ -123,6 +131,12 @@ function get_report_definitions($report_id) { $ds_items = db_custom_fetch_flat_array($sql); + if (!is_array($ds_items)) { + $ds_items = []; + } + + $maxRRDValues = []; + foreach ($ds_items as $key => $data_source_name) { /** * We need to process this list as the maxRRDValue can contain |query_ifSpeed| @@ -189,6 +203,10 @@ function get_report_definitions($report_id) { AND local_data_id = 0', [$template['data_template_id']]); + if (!is_array($tmp)) { + $tmp = []; + } + $template['ds_type'] = $tmp['ds_type']; $template['maximum'] = $tmp['maximum']; @@ -237,37 +255,25 @@ function get_report_definitions($report_id) { * @return int|null The ISO-8601 day number (1=Monday..7=Sunday), or * null if $day doesn't match a known weekday name. */ -function day_to_number($day) { +function day_to_number(string $day): int|null { switch($day) { case __('Monday', 'reportit'): return 1; - - break; case __('Tuesday', 'reportit'): return 2; - - break; case __('Wednesday', 'reportit'): return 3; - - break; case __('Thursday', 'reportit'): return 4; - - break; case __('Friday', 'reportit'): return 5; - - break; case __('Saturday', 'reportit'): return 6; - - break; case __('Sunday', 'reportit'): return 7; - - break; } + + return null; } /** @@ -278,28 +284,28 @@ function day_to_number($day) { * Called from get_prepared_data() while assembling a report's raw RRD * data extraction plan. * - * @param string $startday The report's starting weekday name. - * @param string $endday The report's ending weekday name. - * @param int $f_sp The first data point's start time. - * @param int $l_sp The last data point's start time. - * @param int $e_hour The report's end hour. - * @param int $shift_duration The report's shift duration in - * seconds. - * @param int $rrd_sp The RRD's actual first data point - * time. - * @param int $rrd_ep The RRD's actual last data point - * time. - * @param int $rrd_step The RRD's step size in seconds. - * @param int $rrd_ds_cnt The number of data sources in the - * RRD. - * @param bool $dst_support Whether DST-aware time handling is - * enabled. + * @param int $startday The report's starting weekday name. + * @param int $endday The report's ending weekday name. + * @param int $f_sp The first data point's start time. + * @param int $l_sp The last data point's start time. + * @param int $e_hour The report's end hour. + * @param int $shift_duration The report's shift duration in + * seconds. + * @param int $rrd_sp The RRD's actual first data point + * time. + * @param int $rrd_ep The RRD's actual last data point + * time. + * @param int $rrd_step The RRD's step size in seconds. + * @param int $rrd_ds_cnt The number of data sources in the + * RRD. + * @param bool $dst_support Whether DST-aware time handling is + * enabled. * - * @return array The computed request-type/adaptation parameters used to - * extract the requested data subset from the RRD. + * @return array|false The computed request-type/adaptation parameters used to + * extract the requested data subset from the RRD. */ -function get_type_of_request($startday, $endday, $f_sp, $l_sp, $e_hour, $shift_duration, - $rrd_sp, $rrd_ep, $rrd_step, $rrd_ds_cnt, $dst_support) { +function get_type_of_request(int $startday, int $endday, int $f_sp, int $l_sp, int $e_hour, int $shift_duration, + int $rrd_sp, int $rrd_ep, int $rrd_step, int $rrd_ds_cnt, bool $dst_support): array|false { /** * ----------------------------------------------------------------------------------------------------------- * Calculate all included weekdays @@ -314,6 +320,13 @@ function get_type_of_request($startday, $endday, $f_sp, $l_sp, $e_hour, $shift_d * ----------------------------------------------------------------------------------------------------------- */ + $startday = (int) $startday; + $endday = (int) $endday; + + $wdays = []; + $dis = 0; + $off = 7; + // ----- Calculate all included weekdays ----- switch ($startday) { case $startday == $endday: // e.g. 'Monday till Monday => includes only Monday!' @@ -401,7 +414,7 @@ function get_type_of_request($startday, $endday, $f_sp, $l_sp, $e_hour, $shift_d // Memorize the correct index number if the current wday matches and ... if (in_array($date['wday'], $wdays, true)) { // ...calculate start point's index - $index = floor(($f_sp - $rrd_sp) / $rrd_step + 1); + $index = (int) floor(($f_sp - $rrd_sp) / $rrd_step + 1); // ...if the tmz has been changed calculate the new number of rrd_steps if ($tmz_change) { @@ -482,7 +495,7 @@ function get_type_of_request($startday, $endday, $f_sp, $l_sp, $e_hour, $shift_d // Memorize the correct index number: // ...calculate start point's index - $index = floor(($f_sp - $rrd_sp) / $rrd_step + 1); + $index = (int) floor(($f_sp - $rrd_sp) / $rrd_step + 1); // ...if the tmz has been changed calculate the new number of rrd_steps if ($tmz_change) { @@ -510,10 +523,6 @@ function get_type_of_request($startday, $endday, $f_sp, $l_sp, $e_hour, $shift_d // Break out if $l_sp has been exceeded if ($f_sp > $l_sp) { - if ($ldis == 0) { - $offs--; - } - break 2; } } @@ -568,7 +577,10 @@ function get_type_of_request($startday, $endday, $f_sp, $l_sp, $e_hour, $shift_d * @return array The extracted, corrected data values per data source * index, ready for calculation. */ -function get_prepared_data(&$rrd_data, &$rrd_ad_data, $rrd_ds_cnt, $ds_type, $corr_factor_start, $corr_factor_end, &$ds_namv, &$rrd_nan) { +function get_prepared_data(array &$rrd_data, array &$rrd_ad_data, int $rrd_ds_cnt, int $ds_type, float $corr_factor_start, float $corr_factor_end, array &$ds_namv, &$rrd_nan): array { + $data = []; + $multi = []; + for ($i = 0; $i < $rrd_ds_cnt; $i++) { if (!array_key_exists($i, $ds_namv)) { continue; @@ -626,12 +638,12 @@ function get_prepared_data(&$rrd_data, &$rrd_ad_data, $rrd_ds_cnt, $ds_type, $co * Called via array_walk() from transform() to normalize every raw RRD * sample value. * - * @param string $value Reference, the raw value to normalize in place. + * @param mixed $value Reference, the raw value to normalize in place. * * @return void */ -function strtoNaN(&$value) { - $value = str_replace(',', '.', $value); +function strtoNaN(&$value): void { + $value = str_replace(',', '.', (string) $value); $value = (is_numeric($value)) ? doubleval($value) : REPORTIT_NAN; } @@ -656,13 +668,13 @@ function strtoNaN(&$value) { * otherwise no explicit return (result is populated * into $rrd_data by reference). */ -function transform(&$data, &$rrd_data, &$template) { +function transform(string $data, array &$rrd_data, array &$template) { // Transform into the 'normal' form: - $ds_names = substr($data, 0, strpos($data, PHP_EOL)); + $ds_names = substr($data, 0, (int) strpos($data, PHP_EOL)); $ds_names = str_replace('timestamp', '', $ds_names); debug($ds_names, 'Data sources'); - $data = substr($data, strpos($data, PHP_EOL)); + $data = substr($data, (int) strpos($data, PHP_EOL)); preg_match_all('/\S+/', $ds_names, $rrd_data); debug($rrd_data, 'Preg_match_all'); @@ -676,7 +688,7 @@ function transform(&$data, &$rrd_data, &$template) { $last_timestamp = $zahl - $rrd_data['ds_cnt'] - 1; // catch a cases with a missing data source - if (!isset($data[0]) || !cacti_sizeof($data[0])) { + if (!cacti_sizeof($data[0])) { return false; } @@ -691,13 +703,15 @@ function transform(&$data, &$rrd_data, &$template) { $i = 0; + $array = []; + foreach ($template['RRA'] as $key => $array) { if ($diff > $array['timespan']) { $i++; } } - if ($diff > $array['timespan']) { + if ($diff > ($array['timespan'] ?? 0)) { $i--; } @@ -743,7 +757,7 @@ function transform(&$data, &$rrd_data, &$template) { * @return bool True if the timezone may observe DST, false for * UTC/GMT/UCT. */ -function check_DST_support() { +function check_DST_support(): bool { $tmz = date('T'); $return = ($tmz == 'UTC' || $tmz == 'GMT' || $tmz == 'UCT') ? false : true; @@ -759,7 +773,7 @@ function check_DST_support() { * * @return void */ -function check_rra_header(&$rra_data) { +function check_rra_header(array &$rra_data): void { } /** @@ -781,12 +795,16 @@ function check_rra_header(&$rra_data) { * 'Export Failed' if the report's data couldn't be * retrieved. */ -function reportit_prepare_store_report_results($report_id, $queue_id = 0, $start_time = false) { +function reportit_prepare_store_report_results(int $report_id, int $queue_id = 0, $start_time = false) { $report = db_fetch_row_prepared('SELECT * FROM plugin_reportit_reports WHERE id = ?', [$report_id]); + if (!is_array($report)) { + $report = []; + } + $attachments = []; $data = get_prepared_report_data($report_id, 'export'); $search = ['|title|', '|period|']; @@ -826,7 +844,7 @@ function reportit_prepare_store_report_results($report_id, $queue_id = 0, $start } $filebase = $dirbase . '/' . $filebase . ".$file_type"; - $filename = str_replace('', $report_id, $filebase); + $filename = str_replace('', (string) $report_id, $filebase); $export_function = 'export_to_' . $format; print "Attachment: $filename\n"; @@ -851,7 +869,9 @@ function reportit_prepare_store_report_results($report_id, $queue_id = 0, $start $headers['User-Agent'] = 'Cacti-ReportIt-Report-v' . $v; - $result = reports_log_and_notify($queue_id, $start_time, 'html', 'reportit', $report_id, $subject, $data, $body, $body_html, $body_text, $attachments, $headers); + $body_text = $body; + + $result = reports_log_and_notify($queue_id, (int) $start_time, 'html', 'reportit', $report_id, $subject, $data, $body, $body_html, $body_text, $attachments, $headers); if ($filename != '') { unlink($filename); @@ -873,7 +893,7 @@ function reportit_prepare_store_report_results($report_id, $queue_id = 0, $start * * @return mixed The result of the underlying notification dispatch. */ -function send_scheduled_email($id, $report_id) { +function send_scheduled_email(int $id, int $report_id) { $start_time = microtime(true); // load report based email settings @@ -882,6 +902,10 @@ function send_scheduled_email($id, $report_id) { WHERE id = ?', [$report_id]); + if (!is_array($report_settings)) { + $report_settings = []; + } + $data = ''; $search = ['|title|', '|period|']; $replace = [$report_settings['description'], $report_settings['start_date'] . '-' . $report_settings['end_date']]; @@ -904,6 +928,10 @@ function send_scheduled_email($id, $report_id) { WHERE report_id = ?', [$report_id]); + if (!is_array($to)) { + $to = []; + } + if ($report_settings['email'] != '') { $emails = explode(',', $report_settings['email']); $to += $emails; @@ -915,7 +943,7 @@ function send_scheduled_email($id, $report_id) { $bcc = []; } - if (api_plugin_installed('thold') && $report['notify_list'] > 0) { + if (api_plugin_installed('thold') && $report_settings['notify_list'] > 0) { $nl_to_emails = get_notification_emails($report_settings['notify_list'], 'to'); $nl_bcc_emails = get_notification_emails($report_settings['notify_list'], 'bcc'); @@ -930,7 +958,7 @@ function send_scheduled_email($id, $report_id) { // function mailer($from, $to, $cc, $bcc, $replyto, $subject, $body, $body_text, $attachments, $headers, $html, $epandsIds); - $return = mailer($from, $to, '', $bcc, '', $subject, $body, '', [$attachment], '', true); + $return = mailer($from, $to, '', $bcc, '', $subject, $body, '', [], [], true); return $return; } diff --git a/lib/funct_shared.php b/lib/funct_shared.php index 22419a5..831f26c 100644 --- a/lib/funct_shared.php +++ b/lib/funct_shared.php @@ -34,7 +34,7 @@ * 'Unknown Owner' string if the report/user is not * found. */ -function owner($report_id) { +function owner(int $report_id): string { $tmp = db_fetch_row_prepared('SELECT b.username, b.full_name FROM plugin_reportit_reports as a INNER JOIN user_auth as b @@ -42,7 +42,7 @@ function owner($report_id) { WHERE a.id = ?' , [$report_id]); - if (cacti_sizeof($tmp)) { + if (is_array($tmp) && cacti_sizeof($tmp)) { return $tmp['full_name'] . ' (' . $tmp['username'] . ')'; } else { return __('Unknown Owner', 'reportit'); @@ -70,7 +70,7 @@ function owner($report_id) { * report_variables, report_ds_alias), or false if * the report doesn't exist. */ -function get_prepared_report_data($report_id, $type, $sql_where = '') { +function get_prepared_report_data(int $report_id, string $type, string $sql_where = ''): array|false { $report_measurands = []; $report_variables = []; @@ -82,7 +82,7 @@ function get_prepared_report_data($report_id, $type, $sql_where = '') { WHERE a.id = ?', [$report_id]); - if (!sizeof($report_data)) { + if (!is_array($report_data) || !cacti_sizeof($report_data)) { return false; } @@ -114,6 +114,8 @@ function get_prepared_report_data($report_id, $type, $sql_where = '') { FROM plugin_reportit_data_source_items WHERE template_id = ' . $report_data['template_id'], 'data_source_name', false, false); + $sql = ''; + switch ($type) { case 'view': case 'export': @@ -136,8 +138,6 @@ function get_prepared_report_data($report_id, $type, $sql_where = '') { 'report_data' => $report_data, 'report_measurands' => $report_measurands ]; - - break; } $report_results = db_fetch_assoc($sql); @@ -173,7 +173,7 @@ function get_prepared_report_data($report_id, $type, $sql_where = '') { * @return array|false The assembled data package, or false if the * archived report doesn't exist. */ -function get_prepared_archive_data($cache_id, $type, $sql_where = '') { +function get_prepared_archive_data(string $cache_id, string $type, string $sql_where = ''): array|false { $report_measurands = []; $report_variables = []; @@ -183,9 +183,15 @@ function get_prepared_archive_data($cache_id, $type, $sql_where = '') { WHERE cache_id = ?', [$cache_id]); + if (!is_array($report_data)) { + return false; + } + + $report_ds_alias = []; + // save serialized data source alias separately if (isset($report_data['data_template_alias'])) { - $report_ds_alias = json_decode(base64_decode($report_data['data_template_alias'], true), true); + $report_ds_alias = json_decode((string) base64_decode($report_data['data_template_alias'], true), true); unset($report_data['data_template_alias']); } @@ -207,6 +213,8 @@ function get_prepared_archive_data($cache_id, $type, $sql_where = '') { WHERE cache_id = ?', [$cache_id]); + $sql = ''; + switch ($type) { case 'export': $sql = 'SELECT * FROM plugin_reportit_tmp_' . $cache_id . ' as a ' . $sql_where; @@ -221,8 +229,6 @@ function get_prepared_archive_data($cache_id, $type, $sql_where = '') { 'report_data' => $report_data, 'report_measurands' => $report_measurands ]; - - break; case 'view': $sql = 'SELECT * FROM plugin_reportit_tmp_' . $cache_id . ' AS a ' . $sql_where; @@ -246,15 +252,15 @@ function get_prepared_archive_data($cache_id, $type, $sql_where = '') { /** * db_custom_fetch_assoc() * - * @param string $sql contains the SQL call - * @param string $index contains the name of the column which should be used as index - * if false (default) the index will numerical beginning from zero. - * @param binary $multi save the columns multidimensional. if false then you will get only one result per index - * @param binary $assoc if true (default) then save the $values associated ($key => $value) into the index array - * requires that $multi is true. - * @return binary returns an array or false if the SQL command failed + * @param string $sql contains the SQL call + * @param string|false $index contains the name of the column which should be used as index + * if false (default) the index will numerical beginning from zero. + * @param bool $multi save the columns multidimensional. if false then you will get only one result per index + * @param bool $assoc if true (default) then save the $values associated ($key => $value) into the index array + * requires that $multi is true. + * @return array|false returns an array or false if the SQL command failed */ -function db_custom_fetch_assoc($sql, $index = false, $multi = true, $assoc = true) { +function db_custom_fetch_assoc(string $sql, $index = false, bool $multi = true, bool $assoc = true): array|false { $raw_data = []; $srt_data = []; @@ -292,10 +298,10 @@ function db_custom_fetch_assoc($sql, $index = false, $multi = true, $assoc = tru /** * db_custom_fetch_flat() * returns an numerical array with only one dimension. Every row will be saved column for column. - * @param string $sql contains the SQL call - * @return + * @param string $sql contains the SQL call + * @return array|false */ -function db_custom_fetch_flat_array($sql) { +function db_custom_fetch_flat_array(string $sql): array|false { $raw_data = []; $srt_data = []; @@ -317,11 +323,11 @@ function db_custom_fetch_flat_array($sql) { /** * db_custom_fetch_string() * returns an string. Every row will be saved column for column and separated by a given delimiter. - * @param string $sql contains the SQL call - * @param string $delimiter character for separating the columns. Default is "," - * @return + * @param string $sql contains the SQL call + * @param string $delimiter character for separating the columns. Default is "," + * @return string|false */ -function db_custom_fetch_flat_string($sql, $delimiter = ',') { +function db_custom_fetch_flat_string(string $sql, string $delimiter = ','): string|false { $raw_data = []; $srt_data = ''; @@ -357,11 +363,11 @@ function db_custom_fetch_flat_string($sql, $delimiter = ',') { * @return array The resolved timespan (start/end date components and * related values). */ -function rp_get_timespan($preset_timespan, $present, $enable_tmz = false) { +function rp_get_timespan(string $preset_timespan, $present, bool $enable_tmz = false): array { // Set preconditions $today = ($enable_tmz) ? gmdate('Y-m-d') : date('Y-m-d'); - [$ys, $ms, $ds] = explode('-', $today); - [$ye, $me, $de] = explode('-', $today); + [$ys, $ms, $ds] = array_map('intval', explode('-', $today)); + [$ye, $me, $de] = array_map('intval', explode('-', $today)); // Set report start date switch ($preset_timespan) { @@ -403,12 +409,12 @@ function rp_get_timespan($preset_timespan, $present, $enable_tmz = false) { break; case 'Last Week (Sun - Sat)': - $ds -= ($enable_tmz) ? 7 + gmdate('w') : 7 + date('w'); + $ds -= ($enable_tmz) ? 7 + (int) gmdate('w') : 7 + (int) date('w'); $de = $ds + 6; break; case 'Last Week (Mon - Sun)': - $ds -= ($enable_tmz) ? 6 + gmdate('w') : 6 + date('w'); + $ds -= ($enable_tmz) ? 6 + (int) gmdate('w') : 6 + (int) date('w'); $de = $ds + 6; break; @@ -496,12 +502,12 @@ function rp_get_timespan($preset_timespan, $present, $enable_tmz = false) { $dates = []; - $dates['start_date'] = ($enable_tmz) ? gmdate('Y-m-d', gmmktime(0,0,0, $ms, $ds, $ys)) : date('Y-m-d', mktime(0,0,0, $ms, $ds, $ys)); + $dates['start_date'] = ($enable_tmz) ? gmdate('Y-m-d', (int) gmmktime(0,0,0, $ms, $ds, $ys)) : date('Y-m-d', (int) mktime(0,0,0, $ms, $ds, $ys)); if ($present) { $dates['end_date'] = $today; } else { - $dates['end_date'] = ($enable_tmz) ? gmdate('Y-m-d', gmmktime(0,0,0, $me, $de, $ye)) : date('Y-m-d', mktime(0,0,0, $me, $de, $ye)); + $dates['end_date'] = ($enable_tmz) ? gmdate('Y-m-d', (int) gmmktime(0,0,0, $me, $de, $ye)) : date('Y-m-d', (int) mktime(0,0,0, $me, $de, $ye)); } return $dates; @@ -521,7 +527,7 @@ function rp_get_timespan($preset_timespan, $present, $enable_tmz = false) { * @param int $data_precision The number of decimal places to round * the displayed value to. * - * @return string The formatted value with its unit prefix suffix. + * @return int|float|string The formatted value with its unit prefix suffix. * * @global float $threshold Cached scaling threshold, initialized once * and reused across calls. @@ -534,7 +540,7 @@ function rp_get_timespan($preset_timespan, $present, $enable_tmz = false) { * @global array $IEC Cached IEC prefix label table, initialized * once and reused across calls. */ -function get_unit($value, $prefixes, $data_type, $data_precision) { +function get_unit(float $value, string $prefixes, $data_type, int $data_precision): int|float|string { global $threshold, $binary, $decimal, $IEC; if (!$threshold) { @@ -609,102 +615,68 @@ function get_unit($value, $prefixes, $data_type, $data_precision) { $value /= $pre['Y']; return (sprintf('%' . $data_precision . $data_type, $value) . " Y$i"); - - break; case ($absolute >= $pre['Y'] * $threshold): $value /= $pre['Y']; return (sprintf('%' . $data_precision . $data_type, $value) . " Y$i"); - - break; case ($absolute >= $pre['Z']): // ZETTA $value /= $pre['Z']; return (sprintf('%' . $data_precision . $data_type, $value) . " Z$i"); - - break; case ($absolute >= $pre['Z'] * $threshold): $value /= $pre['Z']; return (sprintf('%' . $data_precision . $data_type, $value) . " Z$i"); - - break; case ($absolute >= $pre['E']): // EXA $value /= $pre['E']; return (sprintf('%' . $data_precision . $data_type, $value) . " E$i"); - - break; case ($absolute >= $pre['E'] * $threshold): $value /= $pre['E']; return (sprintf('%' . $data_precision . $data_type, $value) . " E$i"); - - break; case ($absolute >= $pre['P']): // PETA $value /= $pre['P']; return (sprintf('%' . $data_precision . $data_type, $value) . " P$i"); - - break; case ($absolute >= $pre['P'] * $threshold): $value /= $pre['P']; return (sprintf('%' . $data_precision . $data_type, $value) . " P$i"); - - break; case ($absolute >= $pre['T']): // TERA $value /= $pre['T']; return (sprintf('%' . $data_precision . $data_type, $value) . " T$i"); - - break; case ($absolute >= $pre['T'] * $threshold): $value /= $pre['T']; return (sprintf('%' . $data_precision . $data_type, $value) . " T$i"); - - break; case ($absolute >= $pre['G']): // GIGA $value /= $pre['G']; return (sprintf('%' . $data_precision . $data_type, $value) . " G$i"); - - break; case ($absolute >= $pre['G'] * $threshold): $value /= $pre['G']; return (sprintf('%' . $data_precision . $data_type, $value) . " G$i"); - - break; case ($absolute >= $pre['M']): // MEGA $value /= $pre['M']; return (sprintf('%' . $data_precision . $data_type, $value) . " M$i"); - - break; case ($absolute >= $pre['M'] * $threshold): $value /= $pre['M']; return (sprintf('%' . $data_precision . $data_type, $value) . " M$i"); - - break; case ($absolute >= $pre['K']): // KILO $value /= $pre['K']; return (sprintf('%' . $data_precision . $data_type, $value) . " $k$i"); - - break; case ($absolute >= $pre['K'] * $threshold): $value /= $pre['K']; return (sprintf('%' . $data_precision . $data_type, $value) . " $k$i"); - - break; default: return sprintf('%' . $data_precision . $data_type, $value); - - break; } } @@ -721,7 +693,7 @@ function get_unit($value, $prefixes, $data_type, $data_precision) { * * @return void */ -function create_rvars_entries($variable_id, $template_id, $default) { +function create_rvars_entries(int $variable_id, int $template_id, $default): void { $ids = db_fetch_assoc_prepared('SELECT id FROM plugin_reportit_reports WHERE template_id = ?', @@ -754,10 +726,10 @@ function create_rvars_entries($variable_id, $template_id, $default) { /** * get_possible_rra_names() * returns an array with all possible names of the Round Robbin Archives for this report template - * @param int $template_id contains the id of the current report template - * @return an array with all possible round robin archives + * @param int $template_id contains the id of the current report template + * @return array with all possible round robin archives */ -function get_possible_rra_names($template_id) { +function get_possible_rra_names(int $template_id): array { // Get all possible names of the RRAs for this type of template $names = []; $array = []; @@ -785,7 +757,7 @@ function get_possible_rra_names($template_id) { * @param boolean $ln returns a line break after every interim result * @return array with the syntax of possible interim results */ -function get_interim_results($measurand_id, $template_id, $ln = false) { +function get_interim_results(int $measurand_id, int $template_id, $ln = false): array { $array = []; $names = []; $interim_results = []; @@ -840,7 +812,7 @@ function get_interim_results($measurand_id, $template_id, $ln = false) { * functions in this file; not used * directly here. */ -function get_possible_variables($template_id) { +function get_possible_variables(int $template_id): array { global $calc_var_names; // Fetch all variables which has been defined for this template @@ -881,7 +853,7 @@ function get_possible_variables($template_id) { * @param int $template_id - the data template id * @return array - array of data query cache variables */ -function get_possible_data_query_variables($template_id) { +function get_possible_data_query_variables(int $template_id): array { // any data query associated with this data template? $available_data_queries = db_fetch_assoc_prepared('SELECT DISTINCT dl.snmp_query_id FROM data_local AS dl @@ -930,7 +902,7 @@ function get_possible_data_query_variables($template_id) { * * @return int '1' if locked, otherwise a falsy/empty value. */ -function get_template_status($template_id) { +function get_template_status(int $template_id): int { // Returns '1' if the template has been locked. $status = db_fetch_cell_prepared('SELECT locked FROM plugin_reportit_templates @@ -950,7 +922,7 @@ function get_template_status($template_id) { * * @return void */ -function in_process($report_id, $status = 1) { +function in_process(int $report_id, int $status = 1): void { $now = date('Y-m-d H:i:s'); db_execute_prepared('UPDATE plugin_reportit_reports @@ -968,7 +940,7 @@ function in_process($report_id, $status = 1) { * * @return int The report's current state code. */ -function stat_process($report_id) { +function stat_process(int $report_id): int { $sql = 'SELECT state FROM plugin_reportit_reports WHERE id = ?'; return db_fetch_cell_prepared($sql, [$report_id]); @@ -985,11 +957,11 @@ function stat_process($report_id) { * * @return string The resolved PHP date() format string. */ -function config_date_format($no_time = true) { +function config_date_format(bool $no_time = true): string { $date_fmt = read_graph_config_option('default_date_format'); $datechar = read_graph_config_option('default_datechar'); - if (!isset($date_fmt)) { + if (empty($date_fmt)) { return ('Y-m-d H:i:s'); } @@ -1051,7 +1023,7 @@ function config_date_format($no_time = true) { * * @return void */ -function debug(&$value, $msg = '', $fmsg = '') { +function debug(&$value, string $msg = '', string $fmsg = ''): void { if (!defined('REPORTIT_DEBUG')) { return; } @@ -1093,7 +1065,7 @@ function debug(&$value, $msg = '', $fmsg = '') { * * @return mixed The queried cell value. */ -function get_report_setting($report_id, $column) { +function get_report_setting(int $report_id, string $column) { $sql = 'SELECT $column FROM plugin_reportit_reports WHERE id = ?'; return db_fetch_cell_prepared($sql, [$report_id]); @@ -1111,7 +1083,7 @@ function get_report_setting($report_id, $column) { * @return mixed The user's stored value, or the system default if none * is stored. */ -function get_graph_config_option($config_name, $user_id) { +function get_graph_config_option(string $config_name, int $user_id) { $sql = 'SELECT value FROM settings_graphs WHERE name = ? AND user_id = ?'; $db_setting = db_fetch_row_prepared($sql, [$config_name, $user_id]); @@ -1139,7 +1111,7 @@ function get_graph_config_option($config_name, $user_id) { * @return int The chosen scale exponent (0 for no scaling), or 0 if all * values are zero. */ -function auto_rounding(&$values, $rounding, $order) { +function auto_rounding(array &$values, int $rounding, string $order): int { $threshold = 0.5; $base = ($rounding == 2) ? 1000 : 1024; @@ -1190,7 +1162,7 @@ function auto_rounding(&$values, $rounding, $order) { * * @return void */ -function load_external_libs($name) { +function load_external_libs(string $name): void { switch ($name) { case 'pclzip': if (!defined('PCLZIP_TEMPORARY_DIR')) { @@ -1217,7 +1189,7 @@ function load_external_libs($name) { * * @return void */ -function clean_for_sql(&$str) { +function clean_for_sql(string &$str): void { $str = substr($str, 0, strlen($str) - 1); } @@ -1233,7 +1205,7 @@ function clean_for_sql(&$str) { * * @return int Always 1 (PclZip success code). */ -function rename_xml_file($p_event, &$p_header) { +function rename_xml_file(string $p_event, array &$p_header): int { $p_header['stored_filename'] = $p_header['mtime'] . '.xml'; return 1; @@ -1249,14 +1221,18 @@ function rename_xml_file($p_event, &$p_header) { * * @return string The JSON-encoded report data. */ -function prepare_json_archive($report_id) { +function prepare_json_archive(int $report_id): string { // load report data $data = get_prepared_report_data($report_id, 'view'); + if (!is_array($data)) { + return ''; + } + // transform the data source aliases to the old style $data['report_data']['data_template_alias'] = $data['report_ds_alias']; - return json_encode($data); + return (string) json_encode($data); } /** @@ -1271,7 +1247,7 @@ function prepare_json_archive($report_id) { * * @return void This function calls die() on a PclZip archive error. */ -function update_xml_archive($report_id) { +function update_xml_archive(int $report_id): void { $arc_path = read_config_option('reportit_arc_folder'); $arc_path .= (substr($arc_path, -1) == '/') ? '' : '/'; $tmp_path = REPORTIT_TMP_FD; @@ -1283,6 +1259,10 @@ function update_xml_archive($report_id) { // load report data $data = get_prepared_report_data($report_id, 'view'); + if (!is_array($data)) { + return; + } + // transform the data source aliases to the old style $data['report_data']['data_template_alias'] = serialize($data['report_ds_alias']); @@ -1292,7 +1272,7 @@ function update_xml_archive($report_id) { print '' . PHP_EOL . '' . PHP_EOL . '' . PHP_EOL; foreach ($data['report_data'] as $key => $value) { - print "<$key>" . html_escape($value, ENT_NOQUOTES) . "" . PHP_EOL; + print "<$key>" . html_escape($value) . "" . PHP_EOL; } print '' . PHP_EOL . '' . PHP_EOL; @@ -1300,7 +1280,7 @@ function update_xml_archive($report_id) { print '' . PHP_EOL; foreach ($measurand as $key => $value) { - print "<$key>" . html_escape($value, ENT_NOQUOTES) . "" . PHP_EOL; + print "<$key>" . html_escape($value) . "" . PHP_EOL; } print '' . PHP_EOL; } @@ -1310,7 +1290,7 @@ function update_xml_archive($report_id) { print '' . PHP_EOL; foreach ($results as $key => $value) { - print "<_di__$key>" . html_escape($value, ENT_NOQUOTES) . "" . PHP_EOL; + print "<_di__$key>" . html_escape($value) . "" . PHP_EOL; } print '' . PHP_EOL; } @@ -1320,21 +1300,24 @@ function update_xml_archive($report_id) { print '' . PHP_EOL; foreach ($variable as $key => $value) { - print "<$key>" . html_escape($value, ENT_NOQUOTES) . "" . PHP_EOL; + print "<$key>" . html_escape($value) . "" . PHP_EOL; } print '' . PHP_EOL; } print '' . PHP_EOL . '' . PHP_EOL . '' . PHP_EOL; $content = ob_get_clean(); - $content = mb_convert_encoding($content, 'UTF-8', 'ISO-8859-1'); + $content = mb_convert_encoding((string) $content, 'UTF-8', 'ISO-8859-1'); // create a tempary file and save XML output $cfg = $data['report_data']; $tmpfile = REPORTIT_TMP_FD . strtotime($cfg['start_date']) . '_' . strtotime($cfg['end_date']) . '_' . time() . '.xml'; $filehandle = fopen($tmpfile, 'w'); - fwrite($filehandle, $content); - fclose($filehandle); + + if ($filehandle !== false) { + fwrite($filehandle, $content); + fclose($filehandle); + } // load zip file support load_external_libs('pclzip'); @@ -1385,7 +1368,7 @@ function update_xml_archive($report_id) { * @return void This function calls die_html_custom_error() if the * requested archive entry isn't found. */ -function cache_xml_file($report_id, $mtime) { +function cache_xml_file(int $report_id, int $mtime): void { $cache_id = $report_id . '_' . $mtime; $columns = ''; $values = ''; @@ -1425,7 +1408,7 @@ function cache_xml_file($report_id, $mtime) { $data = $archive->extractByIndex($index, PCLZIP_OPT_EXTRACT_AS_STRING); $content = simplexml_load_string($data[0]['content']); $json_content = json_encode($content); - $archive = json_decode($json_content, true); + $archive = json_decode((string) $json_content, true); // transform data and fill up the cache tables trans_array2sql($archive['report']['settings'], $columns, $values, $cache_id); @@ -1484,7 +1467,7 @@ function cache_xml_file($report_id, $mtime) { * @return bool True if the section was non-empty and transformed, * false if $array was empty/not an array. */ -function trans_array2sql(&$array, &$columns, &$values, $cache_id = false) { +function trans_array2sql(array &$array, string &$columns, string &$values, $cache_id = false): bool { $keys = false; $multi = false; $sub_values = ''; @@ -1500,7 +1483,7 @@ function trans_array2sql(&$array, &$columns, &$values, $cache_id = false) { if (cacti_sizeof($array)) { foreach ($array as $key => $value) { if ($key == 'data_template_alias') { - $value = base64_encode(json_encode(unserialize(stripslashes($value), ['allowed_classes' => false]))); + $value = base64_encode((string) json_encode(unserialize(stripslashes($value), ['allowed_classes' => false]))); } if (is_array($value)) { @@ -1557,7 +1540,7 @@ function trans_array2sql(&$array, &$columns, &$values, $cache_id = false) { * formatted date pairs) found in the report's ZIP * archive, or false if the archive has no entries. */ -function info_xml_archive($report_id) { +function info_xml_archive(int $report_id): array|false { $content = []; $arc_path = read_config_option('reportit_arc_folder'); $arc_file = (($arc_path == '') ? REPORTIT_ARC_FD : $arc_path) . "/$report_id" . '.zip'; @@ -1573,7 +1556,7 @@ function info_xml_archive($report_id) { if (($list = $archive->listContent()) != 0) { foreach ($list as $key => $file) { if ($file['status'] == 'ok') { - [$from, $to] = explode('_', str_replace('.xml', '', $file['filename'])); + [$from, $to] = array_map('intval', explode('_', str_replace('.xml', '', $file['filename']))); $content[$file['mtime']] = date($format, $from) . ' -> ' . date($format, $to); } } @@ -1597,7 +1580,7 @@ function info_xml_archive($report_id) { * @return float|string The average value, or an empty string if * $array is empty. */ -function average($array) { +function average(array $array): float|string { if (cacti_sizeof($array) == 0) { return ''; } @@ -1616,7 +1599,7 @@ function average($array) { * * @return void */ -function transform_html_escape(&$data) { +function transform_html_escape(&$data): void { if (!is_array($data)) { html_escape($data); } else { @@ -1649,20 +1632,24 @@ function transform_html_escape(&$data) { * * @param string $val The size string to convert. * - * @return int The equivalent number of bytes. + * @return int|string The equivalent number of bytes, or '-' when unlimited. */ -function return_bytes($val) { +function return_bytes(string $val): int|string { $val = trim($val); $last = strtolower($val[strlen($val) - 1]); $val = substr($val, 0, -1); - switch($last) { - case 'g': - $val *= 1024; - case 'm': - $val *= 1024; - case 'k': - $val *= 1024; + if (is_numeric($val)) { + $val = (int) $val; + + switch($last) { + case 'g': + $val *= 1024; + case 'm': + $val *= 1024; + case 'k': + $val *= 1024; + } } return $val; @@ -1679,9 +1666,9 @@ function return_bytes($val) { * * @return void */ -function transform_htmlspecialchars(&$data) { +function transform_htmlspecialchars(&$data): void { if (!is_array($data)) { - htmlspecialchars($data); + $data = htmlspecialchars((string) $data); } else { foreach ($data as $key_1 => $value_1) { if (is_array($value_1)) { @@ -1716,21 +1703,18 @@ function transform_htmlspecialchars(&$data) { * 'XMB(Y%)' strings, or 'Undetected' if usage couldn't be * computed). */ -function get_mem_usage() { +function get_mem_usage(): array { $memory_system = return_bytes(ini_get('memory_limit')); $memory_used = round(memory_get_usage() / pow(1024,2),2); $memory_peak = round(memory_get_peak_usage() / pow(1024,2),2); - if ($memory_system == -1 || $memory_system == '-') { + if ($memory_system == '-') { $memory_system = 'unlimited'; $memory_used .= 'MB'; $memory_peak .= 'MB'; - } elseif (!is_numeric($memory_used) || !is_numeric($memory_peak) || !is_numeric($memory_system)) { - $memory_used = 'Undetected'; - $memory_peak = 'Undetected'; } else { - $memory_used .= 'MB(' . round($memory_used / $memory_system * 100,2) . '%)'; - $memory_peak .= 'MB(' . round($memory_peak / $memory_system * 100,2) . '%)'; + $memory_used .= 'MB(' . round($memory_used / (int) $memory_system * 100,2) . '%)'; + $memory_peak .= 'MB(' . round($memory_peak / (int) $memory_system * 100,2) . '%)'; } return ['limit' => $memory_system, 'current' => $memory_used, 'peak' => $memory_peak]; @@ -1749,16 +1733,16 @@ function get_mem_usage() { * * @return string The rendered XML text. */ -function xml_to_string($xml_object, $keep_spaces = true) { +function xml_to_string($xml_object, bool $keep_spaces = true): string { $dom = new DOMDocument(); $dom->preserveWhiteSpace = false; $dom->formatOutput = true; - $dom->loadXML($xml_object->asXml()); + $dom->loadXML((string) $xml_object->asXml()); - $output = $dom->saveXML($dom->firstChild); + $output = (string) $dom->saveXML($dom->firstChild); if (!$keep_spaces) { - $output = preg_replace('/(\v|\s)+/','',$output); + $output = (string) preg_replace('/(\v|\s)+/','',$output); } return $output; @@ -1781,11 +1765,12 @@ function xml_to_string($xml_object, $keep_spaces = true) { * @return array|string The converted array, or an empty string if * $xml_object is falsy. */ -function xml_to_array($xml_object, $indexed = false, $log = false) { +function xml_to_array($xml_object, bool $indexed = false, bool $log = false): array|string { static $indent = -1; $indent++; $indent_char = str_repeat(' ',$indent); + /** @var array $out */ $out = []; if (!$xml_object) { @@ -1856,7 +1841,7 @@ function xml_to_array($xml_object, $indexed = false, $log = false) { * @return string|false The rendered XML fragment for this template, or * false if the template doesn't exist. */ -function export_report_template($template_id, $indent = 0) { +function export_report_template(int $template_id, int $indent = 0): string|false { // load template data $template_data = db_fetch_row_prepared('SELECT * FROM plugin_reportit_templates @@ -1864,7 +1849,7 @@ function export_report_template($template_id, $indent = 0) { [$template_id]); // exit if no result has been returned - if ($template_data == false) { + if (!is_array($template_data)) { return false; } @@ -1919,6 +1904,10 @@ function export_report_template($template_id, $indent = 0) { $xml_temp = convert_array2xml($xml_array, $indent); $xml_obj = simplexml_load_string($xml_temp); + if ($xml_obj === false) { + return false; + } + $valid = true; $checksum = ''; @@ -1944,7 +1933,7 @@ function export_report_template($template_id, $indent = 0) { * * @return string The rendered XML text. */ -function convert_array2xml($data, $indent = 0) { +function convert_array2xml($data, int $indent = 0): string { $output = ''; if ($indent < 0) { @@ -1969,7 +1958,7 @@ function convert_array2xml($data, $indent = 0) { $output .= convert_array2xml($value, $indent + 1); $output .= "$pad" . PHP_EOL; } else { - $output .= "$pad<$key>" . html_escape($value, ENT_NOQUOTES) . "" . PHP_EOL; + $output .= "$pad<$key>" . html_escape($value) . "" . PHP_EOL; } } } @@ -1989,7 +1978,7 @@ function convert_array2xml($data, $indent = 0) { * * @return string The concatenated key+value string. */ -function convert_array2string($data) { +function convert_array2string(array $data): string { $str = ''; foreach ($data as $key => $value) { @@ -2026,7 +2015,7 @@ function convert_array2string($data) { * * @return void */ -function clean_xml_waste(&$array, $replace = '') { +function clean_xml_waste(array &$array, string $replace = ''): void { foreach ($array as $key => $value) { $array[$key] = preg_replace('/(^[\{]{2}([0-9]*)[\}]{2}$)/', $replace, $value); } @@ -2039,14 +2028,14 @@ function clean_xml_waste(&$array, $replace = '') { * data source item rows. Called from template_wizard()'s 'import' step * for each confirmed template in the uploaded file. * - * @param object $report_template The parsed XML template element to - * import. - * @param int $data_template_id The Cacti data template id the new - * report template should be based on. + * @param SimpleXMLElement $report_template The parsed XML template element to + * import. + * @param int $data_template_id The Cacti data template id the new + * report template should be based on. * * @return void */ -function import_template($report_template, $data_template_id) { +function import_template($report_template, int $data_template_id): void { $values = ''; $columns = ''; $old = []; @@ -2058,6 +2047,22 @@ function import_template($report_template, $data_template_id) { $template_measurands = xml_to_array($report_template->measurands, true); $template_data_source_items = xml_to_array($report_template->data_source_items, true); + if (!is_array($template_data)) { + $template_data = []; + } + + if (!is_array($template_variables)) { + $template_variables = []; + } + + if (!is_array($template_measurands)) { + $template_measurands = []; + } + + if (!is_array($template_data_source_items)) { + $template_data_source_items = []; + } + $template_data['id'] = 0; $template_data['data_template_id'] = $data_template_id; diff --git a/lib/funct_validate.php b/lib/funct_validate.php index 2d4a152..de3a8d7 100644 --- a/lib/funct_validate.php +++ b/lib/funct_validate.php @@ -33,21 +33,28 @@ * (e.g. XML parsing) where errors are inspected in code rather than * surfaced directly. * - * @param int $errno The PHP error level. - * @param string $errstr The error message text. + * @param int $errno The PHP error level. + * @param string $errstr The error message text. + * @param string $errfile The file the error occurred in (unused; present + * for error-handler signature compatibility). + * @param int $errline The line the error occurred on (unused; present + * for error-handler signature compatibility). * - * @return void + * @return bool Always true, to suppress PHP's normal error handler for + * the captured error. * * @global array|false $error Set here to ['Number' => ..., 'Message' => * ...] describing the captured error. */ -function last_error($errno, $errstr) { +function last_error($errno, $errstr, $errfile = '', $errline = 0): bool { global $error; $error = [ 'Number' => $errno, 'Message' => $errstr ]; + + return true; } /** @@ -80,7 +87,7 @@ function last_error($errno, $errstr) { * @global array $calc_fct_aliases Valid function alias "with * params" tokens. */ -function validate_calc_formula($calc_formula, $calc_intersizes, $calc_var_names, $calc_data_query_variables) { +function validate_calc_formula(string $calc_formula, array $calc_intersizes, array $calc_var_names, array $calc_data_query_variables): string { global $calc_fct_names, $calc_fct_names_params, $calc_fct_aliases; // Valid signs: @@ -211,7 +218,7 @@ function validate_calc_formula($calc_formula, $calc_intersizes, $calc_var_names, * * @return void This function calls exit() and never returns. */ -function die_html_custom_error($msg = '', $top_header = false) { +function die_html_custom_error(string $msg = '', bool $top_header = false): void { $message = ''; $message = ($msg == '') ? 'Validation error' : $msg; @@ -245,7 +252,7 @@ function die_html_custom_error($msg = '', $top_header = false) { * * @return void */ -function input_validate_input_whitelist($value, $valid_list, $undefined = false, $header = true) { +function input_validate_input_whitelist($value, array $valid_list, bool $undefined = false, bool $header = true): void { if ($value == false && $undefined == true) { return; } @@ -270,7 +277,7 @@ function input_validate_input_whitelist($value, $valid_list, $undefined = false, * * @return void */ -function input_validate_input_blacklist($value, $black_list, $undefined = false, $header = true) { +function input_validate_input_blacklist($value, array $black_list, bool $undefined = false, bool $header = true): void { if ($value == false && $undefined == true) { return; } @@ -296,7 +303,7 @@ function input_validate_input_blacklist($value, $black_list, $undefined = false, * * @return void */ -function input_validate_input_key($value, $valid_list, $undefined = false, $header = true) { +function input_validate_input_key($value, array $valid_list, bool $undefined = false, bool $header = true): void { if ($value == false && $undefined == true) { return; } @@ -309,14 +316,14 @@ function input_validate_input_key($value, $valid_list, $undefined = false, $head /** * input_validate_input_limits() * - * @param float $value The input number that has to be checked - * @param float $lower_limit First limiting value - * @param float $upper_limit Second limiting value - * @param binary $inside Returns an error if the value is outside the limits. - * If 'false', function returns an error if value is inside the limits - * @param binary $header show top_header_graph + * @param float $value The input number that has to be checked + * @param float $lower_limit First limiting value + * @param float $upper_limit Second limiting value + * @param bool $inside Returns an error if the value is outside the limits. + * If 'false', function returns an error if value is inside the limits + * @param bool $header show top_header_graph */ -function input_validate_input_limits($value, $lower_limit, $upper_limit, $inside = true, $header = true) { +function input_validate_input_limits($value, $lower_limit, $upper_limit, $inside = true, $header = true): void { if ($inside) { if ($value < $lower_limit && $value > $upper_limit) { die_html_custom_error('', $header); @@ -333,22 +340,22 @@ function input_validate_input_limits($value, $lower_limit, $upper_limit, $inside * validated sections and short-circuiting once any section fails. * Called from validate_xml_template() once per required section. * - * @param object $xml_template Reference, the parsed XML template - * object being validated. - * @param string $section The XML section name to validate. - * @param bool $valid Reference, the running validity flag; - * cleared if this section is missing/ - * malformed. - * @param string $checksum Reference, the running checksum string, - * appended with this section's canonical - * XML text when valid. + * @param SimpleXMLElement $xml_template Reference, the parsed XML template + * object being validated. + * @param string $section The XML section name to validate. + * @param bool $valid Reference, the running validity flag; + * cleared if this section is missing/ + * malformed. + * @param string $checksum Reference, the running checksum string, + * appended with this section's canonical + * XML text when valid. * * @return bool The (possibly newly cleared) $valid flag. */ -function validate_xml_template_section(&$xml_template, $section, &$valid, &$checksum) { +function validate_xml_template_section(&$xml_template, string $section, bool &$valid, string &$checksum): bool { // print "validate_xml_template_section:start(xml_template, $section, $valid, $checksum)\n"; if ($valid) { - if (isset($xml_template->$section) && is_object($xml_template->$section)) { + if (isset($xml_template->$section) && $xml_template->$section instanceof SimpleXMLElement) { $checksum .= xml_to_string($xml_template->$section, false); } else { $valid = false; @@ -367,24 +374,24 @@ function validate_xml_template_section(&$xml_template, $section, &$valid, &$chec * validate_xml_template_section(). Called from validate_uploaded_templates() * to check a parsed template before accepting it for import. * - * @param object $xml_template Reference, the parsed XML template object - * to validate. - * @param bool $valid Reference, set to false if the document or - * any required section is missing/ - * malformed. - * @param string $checksum Reference, accumulates the canonical - * checksum text across all validated - * sections. + * @param SimpleXMLElement $xml_template Reference, the parsed XML template object + * to validate. + * @param bool $valid Reference, set to false if the document or + * any required section is missing/ + * malformed. + * @param string $checksum Reference, accumulates the canonical + * checksum text across all validated + * sections. * * @return void */ -function validate_xml_template(&$xml_template, &$valid, &$checksum) { +function validate_xml_template(&$xml_template, bool &$valid, string &$checksum): void { // print "validate_xml_template:begin(xml_template, $valid, $checksum)\n"; - if (isset($xml_template->reportit) && is_object($xml_template->reportit)) { + if (isset($xml_template->reportit)) { $count = 0; // Loop through the values of the first reportit element (there should be only one) - foreach ($xml_template->reportit[0] as $key => $value) { + foreach (($xml_template->reportit[0] ?? []) as $key => $value) { if ($key == 'hash') { // Lets do some magic and remove the hash, saving it for later $hash = $value; @@ -422,7 +429,7 @@ function validate_xml_template(&$xml_template, &$valid, &$checksum) { * session for import, false otherwise (with a session error * message set describing the failure). */ -function validate_uploaded_templates() { +function validate_uploaded_templates(): bool { // check file transfer if used if (isset($_FILES['file'])) { // check for errors first @@ -478,13 +485,13 @@ function validate_uploaded_templates() { } // try to parse the report template - $xmldata = simplexml_load_string($template_data); + $xmldata = simplexml_load_string((string) $template_data); $checksum = ''; $valid = true; $hash = false; $compatible = false; - if (!is_object($xmldata)) { + if (!($xmldata instanceof SimpleXMLElement)) { session_custom_error_message('file', __('Unable to parse template file.', 'reportit')); } else { // generate a hash to check the data structure and to find changes @@ -508,6 +515,7 @@ function validate_uploaded_templates() { // check dependences with existing data templates... $data_template_id = $report_template->settings->data_template_id; $template_ds_items = $report_template->data_source_items[0]; + $template_ds_names = []; foreach ($template_ds_items as $template_ds_item) { $template_ds_names[] = (string)$template_ds_item->data_source_name; @@ -521,6 +529,10 @@ function validate_uploaded_templates() { $ds_names = db_custom_fetch_assoc($sql,false,false,false); + if (!is_array($ds_names)) { + $ds_names = []; + } + if (in_array($template_ds_names, $ds_names, true) === false) { $report_compatible = true; @@ -567,7 +579,7 @@ function validate_uploaded_templates() { if ($report_compatible) { $tmp_node = $report_template->addChild('data_templates'); - foreach ($data_templates as $id => $name) { + foreach ((array) $data_templates as $id => $name) { $tmp_child = $tmp_node->addChild('data_template'); $tmp_child->addChild('id',$id); $tmp_child->addChild('name',$name); diff --git a/poller_reportit.php b/poller_reportit.php index 9b35d13..fa440c5 100644 --- a/poller_reportit.php +++ b/poller_reportit.php @@ -146,7 +146,7 @@ } } } elseif ($run_id > 0) { - run_report($run_id, $queue_id); + run_report((int) $run_id, (int) $queue_id); } /** @@ -172,7 +172,7 @@ * performed during this report run, for * the summary log line. */ -function run_report($report_id, $queue_id = 0) { +function run_report($report_id, $queue_id = 0): void { global $run_verb, $email_counter, $export_counter; $start = microtime(true); @@ -186,6 +186,10 @@ function run_report($report_id, $queue_id = 0) { WHERE report.id = ?", [$report_id]); + if (!is_array($report)) { + $report = []; + } + if (!cacti_sizeof($report)) { print PHP_EOL . PHP_EOL . 'ERROR: Invalid report ID !' . PHP_EOL; display_help(); @@ -266,7 +270,7 @@ function run_report($report_id, $queue_id = 0) { * @global string $PATH_DID_VIEW View-oriented data-item-id * link template fragment. */ -function run_error($code, $RID = 0, $DID = 0, $notice = '') { +function run_error(int $code, int $RID = 0, int $DID = 0, string $notice = ''): void { global $run_verb, $run_scheduled, $run_return, $run_search, $runtime_messages, $PATH_RID_LOG, $PATH_DID_LOG, $PATH_RID_VIEW, $PATH_DID_VIEW; @@ -275,7 +279,7 @@ function run_error($code, $RID = 0, $DID = 0, $notice = '') { $run_repl_log = [ $notice, $PATH_RID_LOG, $PATH_DID_LOG]; $run_repl_view = [ $notice, $PATH_RID_VIEW, $PATH_DID_VIEW]; - $run_repl_fin = [ $notice, $RID, $DID]; + $run_repl_fin = [ (string) $notice, (string) $RID, (string) $DID]; $run_logging = str_replace($run_search, $run_repl_fin, $runtime_messages[$code]); @@ -311,7 +315,7 @@ function run_error($code, $RID = 0, $DID = 0, $notice = '') { * @param int $start_time The Unix timestamp this run started at, used * for logging/statistics. * - * @return void + * @return mixed * * @global array $timezones Map of timezone identifiers * used when rendering @@ -384,6 +388,13 @@ function runtime($report_id, $queue_id, $start_time = 0) { WHERE id = ?', [$report_id]); + if (!is_array($report_settings)) { + $report_settings = []; + } + + $rs_def = ''; + $sp_def = ''; + // ----- auto clean-up RRDlist ----- autocleanup($report_id); @@ -560,8 +571,8 @@ function runtime($report_id, $queue_id, $start_time = 0) { $shift_endday = day_to_number($report_definitions['data_items'][$i]['end_day']); // ----- Participate reporting times ----- - [$s_hour, $s_min] = explode(':',$s_time); - [$e_hour, $e_min] = explode(':',$e_time); + [$s_hour, $s_min] = array_map('intval', explode(':', $s_time)); + [$e_hour, $e_min] = array_map('intval', explode(':', $e_time)); if ($enable_tmz) { if (!isset($timezones[$timezone])) { @@ -575,8 +586,8 @@ function runtime($report_id, $queue_id, $start_time = 0) { } // ----- Participate reporting start- and enddate ----- - [$s_year, $s_month, $s_day] = explode('-',$s_date); - [$e_year, $e_month, $e_day] = explode('-',$e_date); + [$s_year, $s_month, $s_day] = array_map('intval', explode('-', $s_date)); + [$e_year, $e_month, $e_day] = array_map('intval', explode('-', $e_date)); // ----- Calculate correct timestamps ----- $f_sp = ($enable_tmz) ? gmmktime($s_hour - $offset_hour,$s_min - $offset_min,0,$s_month,$s_day,$s_year) : mktime($s_hour,$s_min,0,$s_month,$s_day,$s_year); @@ -688,7 +699,7 @@ function runtime($report_id, $queue_id, $start_time = 0) { } // ----- Generate all required informations for calculating ----- - $rrd_ad_data = get_type_of_request($shift_startday, $shift_endday, $f_sp, $l_sp, $e_hour, + $rrd_ad_data = get_type_of_request((int) $shift_startday, (int) $shift_endday, (int) $f_sp, (int) $l_sp, $e_hour, $shift_duration, $rrd_f_mp, $rrd_ep, $rrd_step, $rrd_ds_cnt, $dst_support); @@ -898,7 +909,9 @@ function runtime($report_id, $queue_id, $start_time = 0) { // ----- Close socket connection if its open ----- if ($socket_handle != '' && !$run_scheduled) { - disc_rrdtool_server(); + if (function_exists('disc_rrdtool_server')) { + disc_rrdtool_server(); + } } // ----- Make a note of our endpoint ----- @@ -985,7 +998,7 @@ function runtime($report_id, $queue_id, $start_time = 0) { * * @return void */ -function autorrdlist($reportid) { +function autorrdlist($reportid): void { global $timezone, $shifttime, $shifttime2, $weekday; // fetch data for current report @@ -994,6 +1007,10 @@ function autorrdlist($reportid) { WHERE id = ?', [$reportid]); + if (!is_array($report_data)) { + $report_data = []; + } + $header_label = $report_data['description'] . ' ID: ' . $reportid; if ($report_data['host_template_id'] != 0) { @@ -1031,6 +1048,10 @@ function autorrdlist($reportid) { ON a.template_id = b.id WHERE a.id = ?', [$reportid]); + if (!is_array($template_filter)) { + $template_filter = []; + } + $sql_params = []; // Get all RRDs which are not in RRD table and match with filter settings @@ -1144,6 +1165,10 @@ function autorrdlist($reportid) { WHERE id = ?', [$reportid]); + if (!is_array($presets)) { + $presets = []; + } + if (cacti_sizeof($presets)) { $presets['report_id'] = $reportid; @@ -1184,7 +1209,7 @@ function autorrdlist($reportid) { * * @return void */ -function autocleanup($report_id) { +function autocleanup($report_id): void { $data_items = db_custom_fetch_flat_string("SELECT a.id FROM plugin_reportit_data_items AS a LEFT JOIN data_template_data AS b @@ -1210,15 +1235,19 @@ function autocleanup($report_id) { * @param int $report_id The plugin_reportit_reports id whose output * should be exported. * - * @return void + * @return bool */ -function autoexport($report_id) { +function autoexport($report_id): bool { // load report settings $report_settings = db_fetch_row_prepared('SELECT * FROM plugin_reportit_reports WHERE id = ?', [$report_id]); + if (!is_array($report_settings)) { + $report_settings = []; + } + // main export folder $main_folder = read_config_option('reportit_exp_folder'); @@ -1299,7 +1328,7 @@ function autoexport($report_id) { while (false !== ($file = readdir($path_handle))) { if (substr($file, -$file_format_length) == $file_type) { [$start, $end] = explode('_', $file); - [$year, $month, $day] = explode('-', $start); + [$year, $month, $day] = array_map('intval', explode('-', $start)); $files[mktime(0,0,0,$month, $day, $year)] = $file; } @@ -1361,7 +1390,7 @@ function autoexport($report_id) { /** * display_version - displays version information */ -function display_version() { +function display_version(): void { $version = plugin_reportit_version()['version']; print "ReportIt Main Poller, Version $version, " . COPYRIGHT_YEARS . PHP_EOL; } @@ -1373,7 +1402,7 @@ function display_version() { * * @return void */ -function display_help() { +function display_help(): void { display_version(); print PHP_EOL; diff --git a/reportit.php b/reportit.php index b921aed..37af23f 100644 --- a/reportit.php +++ b/reportit.php @@ -95,7 +95,7 @@ * * @return void */ -function report_wizard() { +function report_wizard(): void { $templates_list = []; $templates = []; @@ -113,7 +113,7 @@ function report_wizard() { form_start('reportit.php'); - html_start_box(__('New Report', 'reportit'), '60%', '', '3', 'center', ''); + html_start_box(__('New Report', 'reportit'), '60%', false, 3, 'center', ''); if (cacti_sizeof($templates_list) == 0) { raise_message('no_unlocked', __('There are no unlocked and enabled report templates available (%s locked or disabled).', $templates_locked, 'reportit'), MESSAGE_LEVEL_ERROR); @@ -161,10 +161,10 @@ function report_wizard() { * @global array $item_rows Cacti's standard row-count option list, * used to populate the rows-per-page dropdown. */ -function report_filter() { +function report_filter(): void { global $item_rows; - html_start_box(__('Report Filters', 'reportit'), '100%', '', '3', 'center', 'reportit.php?action=report_add'); + html_start_box(__('Report Filters', 'reportit'), '100%', false, 3, 'center', 'reportit.php?action=report_add'); ?> @@ -266,7 +266,7 @@ function clearFilter() { * @global array $report_schedule_frequency Map of schedule frequency * code => display label. */ -function standard() { +function standard(): void { global $report_actions, $minutes, $report_states, $sched_types, $report_schedule_frequency; $columns = 0; @@ -464,7 +464,7 @@ function standard() { form_start('reportit.php'); - html_start_box('', '100%', '', '3', 'center', ''); + html_start_box('', '100%', false, 3, 'center', ''); html_header_sort_checkbox($desc_array, get_request_var('sort_column'), get_request_var('sort_direction'), false, 'reportit.php'); @@ -506,7 +506,7 @@ function standard() { print "" . html_sources_icon($report['ds_cnt'], __('Edit sources', 'reportit'), __('Add sources', 'reportit')) . ''; if (!$report['locked'] && $report['state'] < 1) { - form_checkbox_cell(__esc('Select %s', $report['name'], 'reportit'), $report['id'], '', 'right'); + form_checkbox_cell(__esc('Select %s', $report['name'], 'reportit'), $report['id'], false, false); } else { print '' . html_lock_icon('on', __('Report has been locked', 'reportit')) . ''; } @@ -536,7 +536,7 @@ function standard() { * * @return void */ -function remove_recipient() { +function remove_recipient(): void { // ================= input validation ================= get_filter_request_var('id'); get_filter_request_var('rec'); @@ -594,7 +594,7 @@ function remove_recipient() { * form-rendering code; not set directly * here. */ -function form_save() { +function form_save(): void { global $templates, $timespans, $frequency, $timezone, $shifttime, $shifttime2, $weekday, $format, $add_recipients; global $timezone, $shifttime, $shifttime2, $weekday; @@ -673,7 +673,7 @@ function form_save() { case 'items': if (isset($post['save_component_rrdlist'])) { // ================= input validation ================= - locked(my_template($post['report_id'])); + locked((int) my_template($post['report_id'])); // ==================================================== // check start and end of shifttime @@ -729,8 +729,8 @@ function form_save() { } if (!is_error_message()) { - [$ys, $ms, $ds] = explode('-', $post['start_date']); - [$ye, $me, $de] = explode('-', $post['end_date']); + [$ys, $ms, $ds] = array_map('intval', explode('-', $post['start_date'])); + [$ye, $me, $de] = array_map('intval', explode('-', $post['end_date'])); if (!checkdate($ms, $ds, $ys)) { session_custom_error_message('start_date', 'Invalid date'); @@ -844,7 +844,7 @@ function form_save() { break; case 'items': // ================= input validation ================= - locked(my_template($post['report_id'])); + locked((int) my_template($post['report_id'])); // ==================================================== // check start and end of shifttime @@ -1042,7 +1042,7 @@ function form_save() { * option list, used on the items * tab. */ -function report_edit() { +function report_edit(): void { global $templates, $timespans, $graph_timespans, $frequency, $archive, $tabs; global $weekday, $timezone, $shifttime, $shifttime2, $format; global $form_array_admin, $form_array_presets, $form_array_general, $form_array_email; @@ -1062,6 +1062,9 @@ function report_edit() { my_report(get_request_var('id')); // ==================================================== + $report_recipients = []; + $rrdlist_data = []; + // load config settings if it's not a new one if (!isempty_request_var('id')) { $report_data = db_fetch_row_prepared('SELECT * @@ -1079,10 +1082,22 @@ function report_edit() { WHERE report_id = ?', [get_request_var('id')]); + if (!is_array($report_data)) { + $report_data = []; + } + + if (!is_array($rrdlist_data)) { + $rrdlist_data = []; + } + + if (!is_array($report_recipients)) { + $report_recipients = []; + } + $header_label = '[edit: ' . $report_data['name'] . ']'; // update rrdlist_data - if ($rrdlist_data) { + if (cacti_sizeof($rrdlist_data)) { $rrdlist_data['timezone'] = array_search($rrdlist_data['timezone'],$timezone, true); $rrdlist_data['start_time'] = array_search($rrdlist_data['start_time'],$shifttime, true); $rrdlist_data['end_time'] = array_search($rrdlist_data['end_time'],$shifttime2, true); @@ -1196,7 +1211,7 @@ function report_edit() { form_start('reportit.php'); } - html_start_box(__('Report Configuration (%s) %s', $tabs[$current_tab], $header_label, 'reportit'), '100%', '', '3', 'center', ''); + html_start_box(__('Report Configuration (%s) %s', $tabs[$current_tab], $header_label, 'reportit'), '100%', false, 3, 'center', ''); switch(get_request_var('tab')) { case 'presets': @@ -1218,7 +1233,7 @@ function report_edit() { html_end_box(); - html_start_box('Individual Email Recipients', '100%', '', '3', 'center', ''); + html_start_box('Individual Email Recipients', '100%', false, 3, 'center', ''); $display_text = [ 'name' => ['display' => __('Name', 'reportit'), 'width' => '50%'], @@ -1286,7 +1301,7 @@ function report_edit() { // ==================== checkpoint ==================== my_report(get_filter_request_var('id')); - locked(my_template(get_filter_request_var('id'))); + locked((int) my_template(get_filter_request_var('id'))); // ==================================================== if (get_request_var('rows') == '-1') { @@ -1300,11 +1315,19 @@ function report_edit() { WHERE id = ?', [get_request_var('id')]); + if (!is_array($report_data)) { + $report_data = []; + } + $template_data = db_fetch_row_prepared('SELECT * FROM plugin_reportit_templates WHERE id = ?', [$report_data['template_id']]); + if (!is_array($template_data)) { + $template_data = []; + } + if (get_request_var('associated') != 'true') { $sql_where = 'WHERE ri.report_id = ? AND dtd.data_template_id = ? AND dtd.local_data_id > 0'; $sql_params[] = get_request_var('id'); @@ -1404,7 +1427,7 @@ function report_edit() { ]; // start with HTML output - html_start_box('', '100%', '', '3', 'center', ''); + html_start_box('', '100%', false, 3, 'center', ''); ?> @@ -1502,7 +1525,7 @@ function clearFilter() { form_start('reportit.php?tab=items&id=' . get_request_var('id')); - html_start_box('', '100%', '', '3', 'center', ''); + html_start_box('', '100%', false, 3, 'center', ''); html_header_sort_checkbox($desc_array, get_request_var('sort_column'), get_request_var('sort_direction'), false, 'reportit.php?action=report_edit&tab=items&id=' . get_request_var('id')); @@ -1708,7 +1731,7 @@ function dyn_admin_tab() { * @global mixed $weekday Reserved/declared for use by included * form-rendering code; not set directly here. */ -function rrdlist_edit() { +function rrdlist_edit(): void { global $timezone, $shifttime, $shifttime2, $weekday; // ================= input validation ================= @@ -1718,7 +1741,7 @@ function rrdlist_edit() { // ==================== checkpoint ==================== my_report(get_request_var('report_id')); - locked(my_template(get_request_var('report_id'))); + locked((int) my_template(get_request_var('report_id'))); // ==================================================== $enable_tmz = read_config_option('reportit_use_tmz'); @@ -1730,7 +1753,11 @@ function rrdlist_edit() { WHERE a.id = ?', [get_request_var('id')]); - if ($rrdlist_data !== false && sizeof($rrdlist_data)) { + if (!is_array($rrdlist_data)) { + $rrdlist_data = []; + } + + if (cacti_sizeof($rrdlist_data)) { set_request_var('report_id', $rrdlist_data['report_id']); } @@ -1740,7 +1767,7 @@ function rrdlist_edit() { form_start('reportit.php?action=rrdlist_edit&tab=items&id=' . get_request_var('id') . '&report_id=' . get_request_var('report_id')); - html_start_box($header_label, '100%', '', '3', 'center', ''); + html_start_box($header_label, '100%', false, 3, 'center', ''); $form_array = [ 'header1' => [ @@ -1873,7 +1900,7 @@ function rrdlist_edit() { * label, used for the RRD items list * bulk actions. */ -function form_actions() { +function form_actions(): void { global $report_actions, $report_states, $rrdlist_actions; // ================= input validation ================= @@ -1921,7 +1948,7 @@ function form_actions() { } } elseif (get_request_var('drp_action') == '6') { // Take Ownership foreach ($selected_items as $id) { - api_reportit_take_ownership($id); + api_reportit_take_ownership($id, (int) my_id()); } } @@ -1934,7 +1961,7 @@ function form_actions() { if (get_request_var('drp_action') == '1') { // Remove Data Source from the Report api_reportit_remove_data_sources(get_request_var('id'), $selected_items); } elseif (get_request_var('drp_action') == '3') { // Add Data Source to the Report - api_reportit_add_data_source(get_request_var('id')); + api_reportit_add_data_source(get_request_var('id'), $selected_items); } elseif (get_request_var('drp_action') == '2') { // Copy RRD's reference settings to all other RRDs api_reportit_update_data_source(get_request_var('id'), get_request_var('reference_items')); } @@ -1978,7 +2005,9 @@ function form_actions() { $reports = []; } - html_start_box($report_actions[get_request_var('drp_action')], '60%', '', '3', 'center', ''); + $section = ''; + + html_start_box($report_actions[get_request_var('drp_action')], '60%', false, 3, 'center', ''); if (cacti_sizeof($reports)) { if (get_request_var('drp_action') == '1') { // Run Report Now @@ -1988,7 +2017,9 @@ function form_actions() { } elseif (get_request_var('drp_action') == '3') { // Duplicate Report $section = '

' . __('Click \'Continue\' to duplicate the following Report configurations. You may also change the title format during this operation.', 'reportit') . '

'; $section .= '

' . __('Title Format:', 'reportit') . '

'; - $section .= '

' . form_text_box('report_addition', __(' (1)', 'reportit'), '', '255', '30', 'text') . '

'; + ob_start(); + form_text_box('report_addition', __(' (1)', 'reportit'), '', '255', '30', 'text'); + $section .= '

' . ob_get_clean() . '

'; } elseif (get_request_var('drp_action') == '4') { // Disable REPORT $section = '

' . __('Click \'Continue\' to Disable the following Report:', 'reportit') . '

'; } elseif (get_request_var('drp_action') == '5') { // Enable REPORT @@ -2021,13 +2052,13 @@ function form_actions() { - + $save_html "; } else { - html_start_box($rrdlist_actions[get_request_var('drp_action')], '60%', '', '3', 'center', ''); + html_start_box($rrdlist_actions[get_request_var('drp_action')], '60%', false, 3, 'center', ''); // Set preconditions $ds_list = []; @@ -2115,7 +2146,7 @@ function form_actions() { } } - if ($ds_list === false || !is_array($ds_list) || empty($ds_list)) { + if (empty($ds_list)) { print "" . __('You must select at least one Report.', 'reportit') . ''; $save_html = ""; @@ -2128,7 +2159,7 @@ function form_actions() { - + diff --git a/setup.php b/setup.php index c91fe29..69f5a23 100644 --- a/setup.php +++ b/setup.php @@ -47,7 +47,7 @@ function plugin_reportit_csp_nonce(): string { * * @return void */ -function plugin_reportit_install() { +function plugin_reportit_install(): void { api_plugin_register_hook('reportit', 'top_header_tabs', 'reportit_show_tab', 'setup.php'); api_plugin_register_hook('reportit', 'top_graph_header_tabs', 'reportit_show_tab', 'setup.php'); api_plugin_register_hook('reportit', 'draw_navigation_text', 'reportit_draw_navigation_text', 'setup.php'); @@ -76,7 +76,7 @@ function plugin_reportit_install() { * * @return bool Always true. */ -function plugin_reportit_uninstall() { +function plugin_reportit_uninstall(): bool { db_execute('DROP TABLE IF EXISTS plugin_reportit_cache_measurands'); db_execute('DROP TABLE IF EXISTS plugin_reportit_cache_reports'); db_execute('DROP TABLE IF EXISTS plugin_reportit_cache_variables'); @@ -101,7 +101,7 @@ function plugin_reportit_uninstall() { * * @return bool The result of reportit_check_upgrade() (always true). */ -function plugin_reportit_check_config() { +function plugin_reportit_check_config(): bool { return reportit_check_upgrade(); } @@ -112,7 +112,7 @@ function plugin_reportit_check_config() { * * @return bool Always true. */ -function plugin_reportit_upgrade() { +function plugin_reportit_upgrade(): bool { reportit_check_upgrade(); return true; @@ -126,9 +126,13 @@ function plugin_reportit_upgrade() { * @return array The plugin's info array, as parsed from the INFO * file's '[info]' section. */ -function plugin_reportit_version() { +function plugin_reportit_version(): array { $info = parse_ini_file(CACTI_PATH_BASE . '/plugins/reportit/INFO', true); + if (!is_array($info) || empty($info['info'])) { + return []; + } + return $info['info']; } @@ -142,7 +146,7 @@ function plugin_reportit_version() { * * @return bool Always true. */ -function reportit_check_upgrade() { +function reportit_check_upgrade(): bool { $files = ['index.php', 'plugins.php', 'poller_reportit.php']; if (isset($_SERVER['PHP_SELF']) && !in_array(basename($_SERVER['PHP_SELF']), $files, true)) { @@ -154,6 +158,10 @@ function reportit_check_upgrade() { $old = db_fetch_row("SELECT * FROM plugin_config WHERE directory='reportit'"); $tables = db_fetch_assoc("SHOW TABLE STATUS WHERE `Name` LIKE 'reportit%'"); + if (!is_array($old)) { + $old = []; + } + if (cacti_sizeof($old) && $current == $old['version']) { // ReportIt is up to date return true; @@ -202,7 +210,7 @@ function reportit_check_upgrade() { * @return bool Always true (this plugin declares no unmet * requirements). */ -function reportit_upgrade_requirements() { +function reportit_upgrade_requirements(): bool { return true; } @@ -216,7 +224,7 @@ function reportit_upgrade_requirements() { * * @return array The $nav array with this plugin's entries added. */ -function reportit_draw_navigation_text($nav) { +function reportit_draw_navigation_text($nav): array { $nav['reportsit.php:'] = [ 'title' => __('Reports', 'reportit'), 'mapping' => 'index.php:', @@ -465,7 +473,7 @@ function reportit_draw_navigation_text($nav) { * plugin's template-editing * error messages when enabled. */ -function reportit_config_arrays() { +function reportit_config_arrays(): void { global $user_auth_realms, $user_auth_realm_filenames, $menu, $messages; reportit_define_constants(); @@ -522,7 +530,7 @@ function reportit_config_arrays() { * @global array $item_rows Cacti's standard row-count option list, * used for row-count settings. */ -function reportit_config_settings() { +function reportit_config_settings(): void { global $tabs, $tabs_graphs, $settings, $settings_user, $item_rows; // presets @@ -676,7 +684,7 @@ function reportit_config_settings() { * * @return bool True if a row with that name exists, false otherwise. */ -function db_setting_exists($setting) { +function db_setting_exists(string $setting): bool { $results = db_fetch_row_prepared('SELECT * FROM settings WHERE name = ?', [$setting]); if (cacti_sizeof($results)) { @@ -695,7 +703,7 @@ function db_setting_exists($setting) { * * @return void */ -function reportit_show_tab() { +function reportit_show_tab(): void { reportit_check_upgrade(); if (api_user_realm_auth('view.php')) { @@ -709,7 +717,7 @@ function reportit_show_tab() { * * @return void */ -function reportit_system_setup() { +function reportit_system_setup(): void { require_once(CACTI_PATH_BASE . '/plugins/reportit/system/install.php'); reportit_system_install(); @@ -725,7 +733,7 @@ function reportit_system_setup() { * * @return void */ -function reportit_define($constant, $value) { +function reportit_define(string $constant, $value): void { if (!defined($constant)) { @define($constant, $value); } @@ -739,7 +747,7 @@ function reportit_define($constant, $value) { * * @return void */ -function reportit_define_constants() { +function reportit_define_constants(): void { // realm IDs which have been defined dynamically by PIA 2.x $view = db_fetch_cell("SELECT id FROM plugin_realms @@ -783,7 +791,7 @@ function reportit_define_constants() { * * @return void */ -function reportit_poller_bottom() { +function reportit_poller_bottom(): void { require_once(CACTI_PATH_LIBRARY . '/api_scheduler.php'); require_once(CACTI_PATH_LIBRARY . '/reports.php'); @@ -983,7 +991,7 @@ function reportit_schedule_report(&$report) { * * @return array The $regex_array with this plugin's patterns added. */ -function reportit_clog_regex_array($regex_array) { +function reportit_clog_regex_array($regex_array): array { $regex_array[] = ['name' => 'RIReport', 'regex' => '( RIReport\[)([, \d]+)(\])', 'func' => 'reportit_clog_regex_report']; $regex_array[] = ['name' => 'RIDataItem', 'regex' => '( RIDataItem\[)([, \d]+)(\])', 'func' => 'reportit_clog_regex_dataitem']; @@ -1003,7 +1011,7 @@ function reportit_clog_regex_array($regex_array) { * * @return string The rendered HTML replacement with report links. */ -function reportit_clog_regex_report($matches) { +function reportit_clog_regex_report($matches): string { $result = $matches[0]; $report_ids = explode(',', str_replace(' ', '', $matches[2])); @@ -1044,7 +1052,7 @@ function reportit_clog_regex_report($matches) { * * @return string The rendered HTML replacement with data item links. */ -function reportit_clog_regex_dataitem($matches) { +function reportit_clog_regex_dataitem($matches): string { $result = $matches[0]; $dataitem_ids = explode(',',str_replace(' ','',$matches[2])); diff --git a/system/install.php b/system/install.php index 41184e4..e3b9eb4 100644 --- a/system/install.php +++ b/system/install.php @@ -31,7 +31,7 @@ * * @return void */ -function reportit_recreate_cache_tables() { +function reportit_recreate_cache_tables(): void { // rebuild the cache tables $tables = [ 'plugin_reportit_cache_measurands', @@ -169,7 +169,7 @@ function reportit_recreate_cache_tables() { * * @return void */ -function reportit_system_install() { +function reportit_system_install(): void { /* * Table `plugin_reportit_reports` * - contains the general definition of reports diff --git a/system/upgrade.php b/system/upgrade.php index fa67554..8f1662a 100644 --- a/system/upgrade.php +++ b/system/upgrade.php @@ -22,15 +22,30 @@ +-------------------------------------------------------------------------+ */ -function reportit_system_upgrade($old_version) { +/** + * Runs the ReportIt schema/data upgrade steps for an existing install, + * migrating tables and columns from older layouts up to the current + * version. Called from reportit_check_upgrade() when the recorded DB + * version differs from the INFO file version. + * + * @param string $old_version The plugin's currently-recorded database + * version to upgrade from. + * + * @return void + */ +function reportit_system_upgrade(string $old_version): void { require_once(CACTI_PATH_BASE . '/lib/api_scheduler.php'); $default_engine = db_fetch_row("SHOW GLOBAL VARIABLES LIKE 'default_storage_engine'"); - if (!sizeof($default_engine)) { + if (!cacti_sizeof($default_engine)) { $default_engine = db_fetch_row("SHOW GLOBAL VARIABLES LIKE 'storage_engine'"); } + if (!is_array($default_engine)) { + $default_engine = []; + } + if (cacti_sizeof($default_engine)) { $engine = $default_engine['Value']; } else { @@ -180,13 +195,9 @@ function reportit_system_upgrade($old_version) { if (cacti_version_compare($old_version, '1.0.2', '<')) { // migrate existing result tables - $result_tables = []; // db_fetch_assoc("SHOW TABLES FROM `$database_default` LIKE 'reportit_result%'"); - - foreach ($result_tables as $index => $arr) { - foreach ($arr as $tbl) { - db_execute("RENAME TABLE `$tbl` TO `plugin_$tbl`"); - } - } + // $result_tables = db_fetch_assoc("SHOW TABLES FROM `$database_default` LIKE 'reportit_result%'"); + // (result-table migration no longer applicable; the source fetch above is + // disabled, so the original rename loop over $result_tables was dead code) } if (cacti_version_compare($old_version, '1.1.0', '<')) { diff --git a/templates.php b/templates.php index b2be0b8..085c5e4 100644 --- a/templates.php +++ b/templates.php @@ -140,7 +140,7 @@ * * @return void */ -function template_tabs($id) { +function template_tabs($id): void { // present a tabbed interface $tabs = [ 'general' => __('General', 'reportit'), @@ -203,7 +203,7 @@ function template_tabs($id) { * with other functions in this * file; not used directly here. */ -function template_wizard($action) { +function template_wizard(string $action): void { global $list_of_data_templates, $known_data_templates, $fields_template_export; switch ($action) { @@ -216,7 +216,7 @@ function template_wizard($action) { form_start('templates.php', 'chk'); - html_start_box(__('New Report Template', 'reportit'), '60%', '', '3', 'left', ''); + html_start_box(__('New Report Template', 'reportit'), '60%', false, 3, 'left', ''); if (cacti_sizeof($list_of_data_templates) == 0) { print " @@ -256,7 +256,7 @@ function template_wizard($action) { form_start('templates.php', 'reportit_upload', true); - html_start_box(__('Import Report Template', 'reportit'), '60%', '', '3', 'center', ''); + html_start_box(__('Import Report Template', 'reportit'), '60%', false, 3, 'center', ''); print " @@ -286,7 +286,7 @@ function template_wizard($action) { top_header(); $data = $_SESSION['sess_reportit']['report_templates']; - $xmldata = simplexml_load_string($data); + $xmldata = simplexml_load_string((string) $data); $header_array = [ 'name' => ['display' => __('Name', 'reportit')], @@ -299,14 +299,14 @@ function template_wizard($action) { form_start('templates.php?action=template_import_wizard'); - html_start_box(__('Summary', 'reportit'), '100%', '', '3', 'center', ''); + html_start_box(__('Summary', 'reportit'), '100%', false, 3, 'center', ''); html_header($header_array); $compatible = false; $report_count = 0; - foreach ($xmldata as $report_template) { + foreach (($xmldata !== false ? $xmldata : []) as $report_template) { $info = $report_template->settings; if ($report_template->compatible) { @@ -343,7 +343,7 @@ function template_wizard($action) { $templates_array = xml_to_array($report_template->data_templates, true); $templates = []; - foreach ($templates_array as $template_item) { + foreach ((is_array($templates_array) ? $templates_array : []) as $template_item) { $templates[$template_item['id']] = $template_item['name']; } @@ -395,7 +395,7 @@ function template_wizard($action) { * * @return void This function calls exit() and never returns normally. */ -function template_export() { +function template_export(): void { // if we are to save this form, instead of display it if (isset_request_var('selected_items')) { $selected_items = sanitize_unserialize_selected_items(get_nfilter_request_var('selected_items')); @@ -433,7 +433,7 @@ function template_export() { * * @return void */ -function template_import() { +function template_import(): void { header('Location: templates.php?action=template_upload_wizard'); // ================= input validation ================= @@ -445,11 +445,11 @@ function template_import() { } $xml_string = $_SESSION['sess_reportit']['report_templates']; - $xml_data = simplexml_load_string($xml_string); + $xml_data = simplexml_load_string((string) $xml_string); $report_count = 0; - foreach ($xml_data as $report_template) { + foreach (($xml_data !== false ? $xml_data : []) as $report_template) { import_template($report_template, get_request_var('tds' . $report_count)); $report_count++; } @@ -471,10 +471,10 @@ function template_import() { * @global array $item_rows Cacti's standard row-count option list, * used to populate the rows-per-page dropdown. */ -function template_filter() { +function template_filter(): void { global $item_rows; - html_start_box(__('Report Templates', 'reportit'), '100%', '', '3', 'center', 'templates.php?action=template_new'); + html_start_box(__('Report Templates', 'reportit'), '100%', false, 3, 'center', 'templates.php?action=template_new'); ?> @@ -599,7 +599,7 @@ function clearFilter() { * in this file; not used * directly here. */ -function templates() { +function templates(): void { global $template_actions, $link_array, $desc_array, $consolidation_functions, $known_data_templates, $list_of_data_templates, $order_array; // ================= input validation and session storage ================= @@ -747,7 +747,7 @@ function templates() { form_hidden_box('tab', 'general', ''); - html_start_box('', '100%', '', '3', 'center', ''); + html_start_box('', '100%', false, 3, 'center', ''); html_header_sort_checkbox($display_text, get_request_var('sort_column'), get_request_var('sort_direction'), false); @@ -833,7 +833,7 @@ function templates() { * with other functions in this * file; not used directly here. */ -function form_save() { +function form_save(): void { global $list_of_data_templates; global $calc_var_names, $rounding, $precision, $type_specifier; @@ -868,7 +868,7 @@ function form_save() { $template_data['export_folder'] = isset($post['export_folder']) ? $post['export_folder'] : ''; $defined_data_sources = array_rekey( - db_fetch_assoc('SELECT id, data_source_name + db_fetch_assoc_prepared('SELECT id, data_source_name FROM data_template_rrd WHERE local_data_id = 0 AND data_template_id = ?', @@ -1081,7 +1081,6 @@ function form_save() { // Check possible dependences with other measurands if (!is_error_message_field('abbreviation') && $post['id'] != 0) { - $dependences = []; $dependencies = []; $new = $post['abbreviation']; @@ -1100,9 +1099,9 @@ function form_save() { [$post['template_id'], $post['id']]); if (cacti_sizeof($dependencies)) { - foreach ($dependences as $key => $value) { - $value['calc_formula'] = str_replace($old, $new, $value['calc_formula']); - $dependences[$key] = $value; + foreach ($dependencies as $key => $value) { + $value['calc_formula'] = str_replace($old, $new, $value['calc_formula']); + $dependencies[$key] = $value; } } } @@ -1143,8 +1142,8 @@ function form_save() { sql_save($measurand_data, 'plugin_reportit_measurands'); // Update dependences if it's necessary - if (isset($dependences) && sizeof($dependencies)) { - update_formulas($dependences); + if (isset($dependencies) && sizeof($dependencies)) { + update_formulas($dependencies); } // Return to list view if it was an existing report @@ -1162,7 +1161,7 @@ function form_save() { * * @return void */ -function template_edit() { +function template_edit(): void { // ================= input validation ================= $id = get_filter_request_var('id', FILTER_VALIDATE_INT, ['default'=>0]); // ==================================================== @@ -1200,7 +1199,7 @@ function template_edit() { * @global array $fields_template_edit The general tab's field * definitions. */ -function templates_general($id) { +function templates_general(int $id): void { global $consolidation_functions, $list_of_data_templates, $fields_template_edit; session_custom_error_display(); @@ -1210,6 +1209,10 @@ function templates_general($id) { FROM plugin_reportit_templates WHERE id = ?', [$id]); + if (!is_array($template_data)) { + $template_data = []; + } + $header_label = __esc('Template [ %s - %s ]', $template_data['name'], $template_data['description'], 'reportit'); } else { $template_data['id'] = 0; @@ -1244,7 +1247,7 @@ function templates_general($id) { form_hidden_box('tab', 'general', ''); - html_start_box($header_label, '100%', '', '3', 'center', ''); + html_start_box($header_label, '100%', false, 3, 'center', ''); draw_edit_form( [ @@ -1279,7 +1282,7 @@ function templates_general($id) { * label, used for the measurands tab's * bulk actions. */ -function form_actions() { +function form_actions(): void { global $template_actions, $variable_actions, $measurand_actions; if (get_nfilter_request_var('tab') == 'general') { @@ -1326,6 +1329,10 @@ function form_actions() { WHERE id = ?', [$selected_items[$i]]); + if (!is_array($template_data)) { + $template_data = []; + } + $template_data['id'] = 0; $template_data['name'] = str_replace(__('', 'reportit'), $template_data['name'], get_request_var('template_addition')); @@ -1402,7 +1409,7 @@ function form_actions() { FROM plugin_reportit_templates WHERE id = ?', [$selected_items[$i]]); - if ($template_data === false || sizeof($template_data) == 0) { + if (!is_array($template_data) || cacti_sizeof($template_data) == 0) { raise_message(2); header('Location: templates.php'); exit; @@ -1458,7 +1465,7 @@ function DownloadStart(url) { WHERE id = ?', [$id]); - if ($template === false) { + if (!is_array($template)) { $template = ['name' => 'Unknown Template', 'description' => '']; } @@ -1485,7 +1492,7 @@ function DownloadStart(url) { form_start('templates.php'); - html_start_box($template_actions[get_request_var('drp_action')], '60%', '', '3', 'center', ''); + html_start_box($template_actions[get_request_var('drp_action')], '60%', false, 3, 'center', ''); if (get_request_var('drp_action') == '1') { // delete report template(s) @@ -1564,7 +1571,7 @@ function DownloadStart(url) { $save_focus = ' class="ui-button ui-corner-all ui-widget ui-state-active"'; $save_html = ""; - if ($ds_list === false || !is_array($ds_list) || empty($ds_list)) { + if (empty($ds_list)) { print " " . __('You must select at least one Report Template.', 'reportit') . ' @@ -1613,8 +1620,10 @@ function DownloadStart(url) { } // Set preconditions - $ds_list = []; - $i = 0; + $ds_list = []; + $variable_ids = []; + $save_html = ''; + $i = 0; foreach ($_POST as $key => $value) { if (strstr($key, 'chk_')) { @@ -1639,7 +1648,7 @@ function DownloadStart(url) { form_start('templates.php?action=template_edit&tab=variables&id=' . get_request_var('id') . '&tab=variables'); - html_start_box($variable_actions[get_request_var('drp_action')], '60%', '', '3', 'center', ''); + html_start_box($variable_actions[get_request_var('drp_action')], '60%', false, 3, 'center', ''); if (get_request_var('drp_action') == '1') { // DELETE REPORT print " @@ -1699,7 +1708,7 @@ function DownloadStart(url) { - + $save_html @@ -1732,8 +1741,10 @@ function DownloadStart(url) { } // Set preconditions - $ds_list = []; - $i = 0; + $ds_list = []; + $measurand_ids = []; + $save_html = ''; + $i = 0; foreach ($_POST as $key => $value) { if (strstr($key, 'chk_')) { @@ -1758,7 +1769,7 @@ function DownloadStart(url) { form_start('measurands.php'); - html_start_box($measurand_actions[get_request_var('drp_action')], '60%', '', '3', 'center', ''); + html_start_box($measurand_actions[get_request_var('drp_action')], '60%', false, 3, 'center', ''); if (get_request_var('drp_action') == '2') { // DELETE REPORT print " @@ -1796,7 +1807,7 @@ function DownloadStart(url) { - + $save_html @@ -1829,7 +1840,7 @@ function DownloadStart(url) { * @global array $desc_array Populated here with the column header * definitions for the sortable table. */ -function variables() { +function variables(): void { global $variable_actions, $link_array, $list_of_modes, $var_types, $desc_array; $desc_array = [ @@ -1893,6 +1904,10 @@ function variables() { WHERE id = ?', [get_request_var('id')]); + if (!is_array($template)) { + $template = []; + } + $i = 0; $header_label = __('Variables [ Template: %s - %s ]', $template['name'], $template['description'], 'reportit'); @@ -1901,7 +1916,7 @@ function variables() { form_hidden_box('tab', 'variables', ''); - html_start_box($header_label, '100%', '', '3', 'center', 'templates.php?action=variable_edit&tab=variables&id=0&template_id=' . get_request_var('id')); + html_start_box($header_label, '100%', false, 3, 'center', 'templates.php?action=variable_edit&tab=variables&id=0&template_id=' . get_request_var('id')); html_header_sort_checkbox($desc_array, get_request_var('sort_column'), get_request_var('sort_direction'), false); @@ -1984,7 +1999,7 @@ function variables() { * display label, used to populate the * input-type dropdown. */ -function variable_edit() { +function variable_edit(): void { global $template_actions, $var_types; // ================= input validation ================= @@ -1994,12 +2009,18 @@ function variable_edit() { template_tabs(get_request_var('id')); + $variable_data = []; + if (!isempty_request_var('id')) { $variable_data = db_fetch_row_prepared('SELECT * FROM plugin_reportit_variables WHERE id = ?', [get_request_var('id')]); + if (!is_array($variable_data)) { + $variable_data = []; + } + $header_label = __('Variable Configuration [ edit: %s ]', $variable_data['name'], 'reportit'); } else { $header_label = __('Variable Configuration [new]', 'reportit'); @@ -2116,7 +2137,7 @@ function change_variable_type(){ form_start('templates.php?action=template_edit&tab=variables&template_id=' . $template_id); } - html_start_box($header_label, '100%', '', '3', 'center', ''); + html_start_box($header_label, '100%', false, 3, 'center', ''); draw_edit_form( [ @@ -2155,26 +2176,36 @@ function change_variable_type(){ * for the measurand's rounding * precision field. */ -function measurand_edit() { +function measurand_edit(): void { global $template_actions, $rounding, $consolidation_functions, $type_specifier, $precision; // ================= input validation ================= get_filter_request_var('id'); // ==================================================== + $measurand_data = []; + $measurand_id = (isset_request_var('id') ? get_request_var('id') : '0'); - $template_id = (isset_request_var('template_id') ? get_request_var('template_id') : $measurand_data['template_id']); + $template_id = (isset_request_var('template_id') ? get_request_var('template_id') : 0); $template = db_fetch_row_prepared('SELECT * FROM plugin_reportit_templates WHERE id = ?', [$template_id]); + if (!is_array($template)) { + $template = []; + } + if (!isempty_request_var('id')) { $measurand_data = db_fetch_row_prepared('SELECT * FROM plugin_reportit_measurands WHERE id = ?', [get_request_var('id')]); + if (!is_array($measurand_data)) { + $measurand_data = []; + } + $header_label = __('Metric Configuration [ edit: %s - %s ]', $template['name'], $measurand_data['description'], 'reportit'); } else { $header_label = __('Metric Configuration [new]', 'reportit'); @@ -2336,7 +2367,7 @@ function add_to_calc(name) { form_start('templates.php?action=template_edit&tab=measurands&id=' . get_request_var('id') . '&template_id=' . $template_id); - html_start_box($header_label, '100%', '', '3', 'center', ''); + html_start_box($header_label, '100%', false, 3, 'center', ''); draw_edit_form( [ @@ -2368,7 +2399,7 @@ function add_to_calc(name) { * display each measurand's * consolidation setting. */ -function measurands() { +function measurands(): void { global $measurand_actions, $consolidation_functions; // ================= input validation ================= @@ -2385,6 +2416,10 @@ function measurands() { WHERE id = ?', [get_request_var('id')]); + if (!is_array($template)) { + $template = []; + } + $i = 0; $header_label = __('Metrics [ Template: %s - %s ]', $template['name'], $template['description'], 'reportit'); @@ -2393,7 +2428,7 @@ function measurands() { form_hidden_box('tab', 'measurands', ''); - html_start_box($header_label, '100%', '', '3', 'center', 'templates.php?action=measurand_edit&tab=measurands&id=0&template_id=' . get_request_var('id')); + html_start_box($header_label, '100%', false, 3, 'center', 'templates.php?action=measurand_edit&tab=measurands&id=0&template_id=' . get_request_var('id')); $display_text = [ __('Name', 'reportit'), @@ -2445,7 +2480,7 @@ function measurands() { html_end_box(true); - draw_actions_dropdown($measurand_actions, 'templates.php?action=template_edit&tab=measurands&id=' . get_request_var('id')); + draw_actions_dropdown($measurand_actions); form_end(); } diff --git a/view.php b/view.php index 7ebb991..a709621 100644 --- a/view.php +++ b/view.php @@ -54,7 +54,10 @@ break; case 'export': general_header(); - show_export_wizard(true); + + if (function_exists('show_export_wizard')) { + show_export_wizard(true); + } bottom_footer(); break; @@ -78,11 +81,11 @@ * * @return void * - * @global array $export_formats Reserved/declared for parity with - * other functions in this file; not used - * directly here. + * @global array $export_formats Allowlist of valid export formats, used + * to constrain the dynamic export dispatch + * to known functions only. */ -function export() { +function export(): void { global $export_formats; $id = validate_report_vars(); @@ -98,6 +101,8 @@ function export() { $sql_order = get_order_string(); + $cache_id = ''; + // get informations about the archive if it exists // $archive = info_xml_archive(get_request_var('id')); @@ -112,9 +117,21 @@ function export() { ? get_prepared_report_data(get_request_var('id'), 'export', $sql_where) : get_prepared_archive_data($cache_id, 'export', $sql_where); - // call export function - $export_function = 'export_to_' . get_request_var('drp_action'); - $output = $export_function($data); + if (!is_array($data)) { + $data = []; + } + + // call export function; restrict dispatch to the known export formats + $format = get_request_var('drp_action'); + $output = ''; + + if (isset($export_formats[$format])) { + $export_function = 'export_to_' . $format; + + if (function_exists($export_function)) { + $output = $export_function($data); + } + } $content_type = strtolower(get_request_var('drp_action')); @@ -148,7 +165,7 @@ function export() { * @global array $item_rows Cacti's standard row-count option list, used * to populate the rows dropdown. */ -function standard() { +function standard(): void { global $item_rows; $myId = my_id(); @@ -231,7 +248,7 @@ function standard() { $sql_params); // start with HTML output - html_start_box(__('Reports Filter', 'reportit'), '100%', '', '3', 'center', ''); + html_start_box(__('Reports Filter', 'reportit'), '100%', false, 3, 'center', ''); ?> @@ -353,7 +370,7 @@ function clearFilter() { print $nav; - html_start_box('', '100%', '', '3', 'center', ''); + html_start_box('', '100%', false, 3, 'center', ''); html_header_sort($desc_array, get_request_var('sort_column'), get_request_var('sort_direction')); @@ -397,7 +414,7 @@ function clearFilter() { * setting disables id persistence and none was * supplied). */ -function validate_report_vars() { +function validate_report_vars(): string { // if the user pushed the 'clear' button $id = (read_graph_config_option('reportit_view_filter') == 'on') ? get_filter_request_var('id') : ''; @@ -497,7 +514,7 @@ function validate_report_vars() { * list, used to populate the rows * dropdown. */ -function show_report() { +function show_report(): void { global $search, $t_limit, $add_info, $export_formats, $item_rows; $limitation = 0; @@ -513,7 +530,9 @@ function show_report() { $rs_description = []; $ov_description = []; $report_summary = []; + /** @var array $archive */ $archive = []; + /** @var array $report_ds_alias */ $report_ds_alias = []; $id = validate_report_vars(); @@ -564,6 +583,10 @@ function show_report() { $data = get_prepared_archive_data($cache_id, 'view', $sql_affix); } + if (!is_array($data)) { + $data = []; + } + // get total number of rows (data items) if (get_request_var('archive') != -1) { $source = 'plugin_reportit_tmp_' . get_request_var('id') . '_' . get_request_var('archive') . ' AS a @@ -672,7 +695,7 @@ function show_report() { // start HTML output $report_header = $data['report_data']['name']; - html_start_box(__($report_header), '100%', '', '3', 'center', ''); + html_start_box(__($report_header), '100%', false, 3, 'center', ''); ob_start(); ?> @@ -863,7 +886,7 @@ function clearFilter() { $report_summary[4][__('Period', 'reportit')] = $data['report_data']['start_date'] . ' - ' . $data['report_data']['end_date']; $report_summary[4][__('Auto Generated RRD list', 'reportit')] = ($data['report_data']['autorrdlist'] == '') ? 'disabled' : 'enabled'; - html_start_box('', '100%', '', '3', 'center', ''); + html_start_box('', '100%', false, 3, 'center', ''); foreach ($report_summary as $array) { print ''; @@ -879,9 +902,9 @@ function clearFilter() { } if (isempty_request_var('graph_mode')) { - show_table_view($data, $ds_description, $rs_description, $ov_description, $count_ov, $count_rs, $columns, $rows, $total_rows); + show_table_view($data, $ds_description, $rs_description, $ov_description, (int) $count_ov, $count_rs, $columns, $rows, $total_rows); } else { - show_graph_view($data, $ds_description, $rs_description, $ov_description, $count_ov, $count_rs); + show_graph_view($data, $ds_description, $rs_description, $ov_description, (int) $count_ov, $count_rs); } } @@ -891,22 +914,22 @@ function clearFilter() { * counts. Called from show_report() when the report's display mode is * set to table view. * - * @param array $data The report's prepared data rows. - * @param array $ds_description Data-source-level measurand - * descriptions. - * @param array $rs_description Result-set-level measurand - * descriptions. - * @param array $ov_description Overview-level measurand descriptions. - * @param int $count_ov The number of overview measurands. - * @param int $count_rs The number of result-set measurands. - * @param int $columns The total number of table columns to - * render. - * @param array $rows The report's data rows to render. - * @param int $total_rows The total row count (for pagination). + * @param array $data The report's prepared data rows. + * @param array $ds_description Data-source-level measurand + * descriptions. + * @param array|false $rs_description Result-set-level measurand + * descriptions. + * @param array|false $ov_description Overview-level measurand descriptions. + * @param int $count_ov The number of overview measurands. + * @param int $count_rs The number of result-set measurands. + * @param int $columns The total number of table columns to + * render. + * @param int $rows The number of rows to display per page. + * @param int $total_rows The total row count (for pagination). * * @return void */ -function show_table_view($data, $ds_description, $rs_description, $ov_description, $count_ov, $count_rs, $columns, $rows, $total_rows) { +function show_table_view(array $data, array $ds_description, $rs_description, $ov_description, int $count_ov, int $count_rs, int $columns, int $rows, int $total_rows): void { global $search, $t_limit, $add_info, $export_formats, $item_rows; $report_ds_alias = $data['report_ds_alias']; @@ -918,7 +941,7 @@ function show_table_view($data, $ds_description, $rs_description, $ov_descriptio $nav = html_nav_bar('view.php?action=show_report&id=' . get_request_var('id'), 20, get_request_var('page'), $rows, $total_rows, $columns, __('Reports', 'reportit'), 'page', 'main'); print $nav; - html_start_box('', '100%', '', '3', 'center', ''); + html_start_box('', '100%', false, 3, 'center', ''); // print table header $display_text = [ @@ -950,7 +973,7 @@ function show_table_view($data, $ds_description, $rs_description, $ov_descriptio } if (isempty_request_var('graph_mode')) { - html_header_sort($display_text, get_request_var('sort_column'), get_request_var('sort_direction'), '1', 'view.php?action=show_report&id=' . get_request_var('id')); + html_header_sort($display_text, get_request_var('sort_column'), get_request_var('sort_direction'), 1, 'view.php?action=show_report&id=' . get_request_var('id')); } // Set preconditions @@ -998,7 +1021,7 @@ function show_table_view($data, $ds_description, $rs_description, $ov_descriptio $name = ($datasource != 'overall') ? $rs_description : $ov_description; $first = ''; - foreach ($name as $id) { + foreach ((array) $name as $id) { $rounding = $mea[$id]['rounding']; $data_type = $mea[$id]['data_type']; $data_precision = $mea[$id]['data_precision']; @@ -1085,18 +1108,18 @@ function show_table_view($data, $ds_description, $rs_description, $ov_descriptio * data source/result-set/overview measurand descriptions. Called from * show_report() when the report's display mode is set to graph view. * - * @param array $data The report's prepared data rows. - * @param array $ds_description Data-source-level measurand - * descriptions. - * @param array $rs_description Result-set-level measurand - * descriptions. - * @param array $ov_description Overview-level measurand descriptions. - * @param int $count_ov The number of overview measurands. - * @param int $count_rs The number of result-set measurands. + * @param array $data The report's prepared data rows. + * @param array $ds_description Data-source-level measurand + * descriptions. + * @param array|false $rs_description Result-set-level measurand + * descriptions. + * @param array|false $ov_description Overview-level measurand descriptions. + * @param int $count_ov The number of overview measurands. + * @param int $count_rs The number of result-set measurands. * * @return void */ -function show_graph_view($data, $ds_description, $rs_description, $ov_description, $count_ov, $count_rs) { +function show_graph_view(array $data, array $ds_description, $rs_description, $ov_description, int $count_ov, int $count_rs): void { global $graphs, $limit; $affix = ''; @@ -1115,7 +1138,7 @@ function show_graph_view($data, $ds_description, $rs_description, $ov_descriptio $description = (is_array($report_ds_alias) && array_key_exists($datasource, $report_ds_alias)) ? ($report_ds_alias[$datasource] != '') ? $report_ds_alias[$datasource] : $datasource : $datasource; - html_start_box(__('Data Source: %s', $description, 'reportit'), '100%', false, '3', 'center', ''); + html_start_box(__('Data Source: %s', $description, 'reportit'), '100%', false, 3, 'center', ''); $name = ($datasource != 'overall') ? $rs_description : $ov_description; @@ -1166,7 +1189,7 @@ function show_graph_view($data, $ds_description, $rs_description, $ov_descriptio print ""; - html_start_box('', '100%', '', '3', 'center', ''); + html_start_box('', '100%', false, 3, 'center', ''); if (cacti_sizeof($data)) { $display_text = [ @@ -1240,7 +1263,7 @@ function show_graph_view($data, $ds_description, $rs_description, $ov_descriptio * * @return void This function calls exit() after issuing the redirect. */ -function show_graph_overview() { +function show_graph_overview(): void { // ================= Input validation ================= input_validate_input_number(get_request_var('id')); input_validate_input_number(get_request_var('rrd')); @@ -1248,6 +1271,8 @@ function show_graph_overview() { // ==================================================== // load report archive and fill up report cache if requested + $cache_id = ''; + if (get_request_var('cache') != -1) { cache_xml_file(get_request_var('id'), get_request_var('cache')); $cache_id = get_request_var('id') . '_' . get_request_var('cache'); @@ -1258,6 +1283,10 @@ function show_graph_overview() { ? get_prepared_report_data(get_request_var('id'),'view') : get_prepared_archive_data($cache_id, 'view'); + if (!is_array($data)) { + $data = []; + } + $report_data = $data['report_data']; $local_graph_id = db_fetch_cell_prepared('SELECT DISTINCT gti.local_graph_id @@ -1290,10 +1319,10 @@ function show_graph_overview() { * * @return string The rendered HTML/JS markup for the treemap chart. */ -function plugin_reportit_graph($graph_id, $graph_data) { +function plugin_reportit_graph($graph_id, $graph_data): string { $content = ''; - $xid = substr(md5($graph_id), 0, 7); + $xid = substr(md5((string) $graph_id), 0, 7); $labels = []; $values = [];