From 26d89db5bcf6d96a2d5490072442d76debb3c4d5 Mon Sep 17 00:00:00 2001 From: Thomas Vincent Date: Mon, 17 Aug 2026 22:19:54 -0700 Subject: [PATCH 1/3] fix: normalize nullable notification text --- CHANGELOG.md | 1 + README.md | 3 +++ tests/Unit/TholdStrReplaceTest.php | 9 +++++++++ thold_functions.php | 4 ++-- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b7db7d7..f37d225a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * issue#710: Fixing Typo in thold_daemons.service File * issue#714: Increase the Name column to 255 characters * issue#719: Plugin Disabled due to mix of string and int +* issue#814: Normalize nullable notification template text before replacement * issue: All Columns checkd on Thresholds page * issue: Special character previous value handling broken on data query indexes with special characters diff --git a/README.md b/README.md index 46310dce..109dc656 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,9 @@ and become familiar with its settings. From there, you can provide overall control of thold, and set defaults for things like Email bodies, weekend exemptions, alert log retention, logging, etc. +Optional notification template fields that are unset are treated as empty +text, so an empty description or replacement does not abort delivery. + As with much of Cacti, settings should be documented in line with the actual setting. If you find that any of these settings are ambiguous, please create a pull request with your proposed changes. diff --git a/tests/Unit/TholdStrReplaceTest.php b/tests/Unit/TholdStrReplaceTest.php index 69006c39..71c20d0c 100644 --- a/tests/Unit/TholdStrReplaceTest.php +++ b/tests/Unit/TholdStrReplaceTest.php @@ -91,4 +91,13 @@ public function testEveryOccurrenceIsReplaced(): void { public function testSubjectWithoutTheTagIsUnchanged(): void { $this->assertSame('no tags here', thold_str_replace('', 5, 'no tags here')); } + + /** + * @return void + */ + public function testNullableInputsAreNormalizedAtTheBoundary(): void { + $this->assertSame('', thold_str_replace('', 'value', null)); + $this->assertSame('subject', thold_str_replace(null, 'value', 'subject')); + $this->assertSame('', thold_str_replace(null, null, null)); + } } diff --git a/thold_functions.php b/thold_functions.php index f195d302..f65295a7 100644 --- a/thold_functions.php +++ b/thold_functions.php @@ -8366,8 +8366,8 @@ function thold_get_cached_name(&$thold_data) { * @param mixed $replace Value to substitute. * @param string $subject Text containing the tag. */ -function thold_str_replace(string $search, $replace, string $subject): string { - return str_replace($search, $replace ?? '', $subject); +function thold_str_replace($search, $replace, $subject): string { + return str_replace((string) ($search ?? ''), (string) ($replace ?? ''), (string) ($subject ?? '')); } function thold_template_import($xml_data) { From 34b20bbf9b12a8f6c7d186988d3df47c86d8e55b Mon Sep 17 00:00:00 2001 From: Thomas Vincent Date: Mon, 17 Aug 2026 22:38:23 -0700 Subject: [PATCH 2/3] fix: preserve notification replacement type checks --- tests/Unit/TholdStrReplaceTest.php | 5 ++--- thold_functions.php | 10 +++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/Unit/TholdStrReplaceTest.php b/tests/Unit/TholdStrReplaceTest.php index 71c20d0c..56daee88 100644 --- a/tests/Unit/TholdStrReplaceTest.php +++ b/tests/Unit/TholdStrReplaceTest.php @@ -95,9 +95,8 @@ public function testSubjectWithoutTheTagIsUnchanged(): void { /** * @return void */ - public function testNullableInputsAreNormalizedAtTheBoundary(): void { + public function testNullableSubjectIsNormalizedAtTheBoundary(): void { $this->assertSame('', thold_str_replace('', 'value', null)); - $this->assertSame('subject', thold_str_replace(null, 'value', 'subject')); - $this->assertSame('', thold_str_replace(null, null, null)); + $this->assertSame('', thold_str_replace('', null, null)); } } diff --git a/thold_functions.php b/thold_functions.php index f65295a7..6ece0f7e 100644 --- a/thold_functions.php +++ b/thold_functions.php @@ -8362,12 +8362,12 @@ function thold_get_cached_name(&$thold_data) { * blanking it produced alert bodies reading "Current value is " for exactly * the case an operator most needs to see. * - * @param string $search Tag to replace. - * @param mixed $replace Value to substitute. - * @param string $subject Text containing the tag. + * @param string $search Tag to replace. + * @param mixed $replace Value to substitute. + * @param string|null $subject Text containing the tag. */ -function thold_str_replace($search, $replace, $subject): string { - return str_replace((string) ($search ?? ''), (string) ($replace ?? ''), (string) ($subject ?? '')); +function thold_str_replace(string $search, $replace, ?string $subject): string { + return str_replace($search, $replace ?? '', $subject ?? ''); } function thold_template_import($xml_data) { From 4036df0ebee7ca9a6bc0c1d8c705bd48cd02335d Mon Sep 17 00:00:00 2001 From: Thomas Vincent Date: Mon, 17 Aug 2026 22:47:28 -0700 Subject: [PATCH 3/3] test: pin nullable subject deprecation handling --- README.md | 3 +-- tests/Unit/TholdStrReplaceTest.php | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 109dc656..4516eda0 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,7 @@ and become familiar with its settings. From there, you can provide overall control of thold, and set defaults for things like Email bodies, weekend exemptions, alert log retention, logging, etc. -Optional notification template fields that are unset are treated as empty -text, so an empty description or replacement does not abort delivery. +An unset notification template field is treated as empty text. As with much of Cacti, settings should be documented in line with the actual setting. If you find that any of these settings are ambiguous, please create a diff --git a/tests/Unit/TholdStrReplaceTest.php b/tests/Unit/TholdStrReplaceTest.php index 56daee88..9e31619c 100644 --- a/tests/Unit/TholdStrReplaceTest.php +++ b/tests/Unit/TholdStrReplaceTest.php @@ -96,7 +96,24 @@ public function testSubjectWithoutTheTagIsUnchanged(): void { * @return void */ public function testNullableSubjectIsNormalizedAtTheBoundary(): void { - $this->assertSame('', thold_str_replace('', 'value', null)); - $this->assertSame('', thold_str_replace('', null, null)); + $deprecations = []; + set_error_handler(static function ($severity, $message) use (&$deprecations) { + if ($severity === E_DEPRECATED) { + $deprecations[] = $message; + + return true; + } + + return false; + }); + + try { + $this->assertSame('', thold_str_replace('', 'value', null)); + $this->assertSame('', thold_str_replace('', null, null)); + } finally { + restore_error_handler(); + } + + $this->assertSame([], $deprecations); } }