From 777b42d6f8f280a1f7ad2c361631ba09222be1c2 Mon Sep 17 00:00:00 2001 From: TheWitness Date: Thu, 8 Oct 2026 14:52:10 -0400 Subject: [PATCH 1/2] Guard pre-1.3 report shims with function_exists to avoid redeclare fatal functions-pre13.php unconditionally defines reports_run/reports_queue/reports_log_and_notify, which are native in Cacti 1.3. A develop build can report a version comparing < 1.3 while already defining them, so the version_compare gate loaded the shims and fatally redeclared them. Gate on function_exists('reports_run') instead. --- CHANGELOG.md | 1 + includes/functions.php | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50a4ee8..5ba19b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ --- develop --- +* bug: Guard the pre-1.3 report compatibility shims (reports_run/reports_queue/reports_log_and_notify) behind a function_exists() check instead of a CACTI_VERSION string comparison, so a develop build that reports a version comparing < 1.3 no longer fatally redeclares those now-native functions * security: Move the plugin's remaining inline event handlers to CSP-safe bindings so the pages no longer trip Cacti's Content-Security-Policy script-src-attr directive: confirmation Cancel buttons use the `cactiReturnTo` class, the database/filter selects are bound via change() in their ready blocks, and the main filter's sort/report selects and time-shift icons are bound in flowview_display_filter's ready block * dev: Replace the translation-template CI check that regenerated locales/po/cacti.pot and compared it with a diff-based gate (tests/bin/check-i18n-pot.php) requiring cacti.pot to be updated only when a pull request adds, removes, or modifies an i18n function call * issue: Prevent flow-capture from fatally erroring (TypeError in spl_object_hash) when flowview_db_check_reconnect() held a null shared-database handle; normalize a non-object connection to false so db_check_reconnect() checks and reconnects the default connection instead diff --git a/includes/functions.php b/includes/functions.php index 9c41102..55a1850 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -23,7 +23,11 @@ +-------------------------------------------------------------------------+ */ -if (version_compare(CACTI_VERSION, '1.3', '<')) { +// reports_run()/reports_queue()/reports_log_and_notify() are native in Cacti +// 1.3+. Load the compat shims only when they are actually missing: a develop +// build can report a version that compares < 1.3 while already defining them +// natively, and unconditionally including the shims would fatally redeclare them. +if (!function_exists('reports_run')) { require_once(__DIR__ . '/functions-pre13.php'); } From 15082a235a644b1c94de2c2147a845aef56676b5 Mon Sep 17 00:00:00 2001 From: TheWitness Date: Thu, 8 Oct 2026 15:27:49 -0400 Subject: [PATCH 2/2] Add regression test: functions.php must not redeclare native report helpers Addresses PR review: CI checks out Cacti 1.2.x (report helpers absent) and the bootstrap already loaded functions.php, so the develop-only 'natives present' path is not covered in-process. Add an isolated child-process test that defines reports_run/reports_queue/reports_log_and_notify, requires functions.php, and asserts it loads without a redeclaration. --- tests/Unit/ReportsShimGuardTest.php | 50 +++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 tests/Unit/ReportsShimGuardTest.php diff --git a/tests/Unit/ReportsShimGuardTest.php b/tests/Unit/ReportsShimGuardTest.php new file mode 100644 index 0000000..a24d538 --- /dev/null +++ b/tests/Unit/ReportsShimGuardTest.php @@ -0,0 +1,50 @@ +toBeTrue(); + + $script = <<<'CHILD' +>>'; +CHILD; + + $tmp = tempnam(sys_get_temp_dir(), 'pre13_'); + expect($tmp)->not->toBeFalse(); + + try { + file_put_contents($tmp, $script); + + $command = escapeshellarg(PHP_BINARY) . ' ' . escapeshellarg($tmp) . ' ' . escapeshellarg($functions); + $output = (string) shell_exec($command); + + expect($output)->toContain('<<>>'); + expect($output)->not->toContain('redeclare'); + } finally { + @unlink($tmp); + } +});