62 Commits
Author SHA1 Message Date
TheWitnessandTheWitness 3b3544db03 Add MySQL/MariaDB variable capability matrix to Database section (#8188)
* Add MySQL/MariaDB variable capability matrix to Database section

* Add changelog fragment for PR #8188

* Address review: correct version boundaries, escaping, valid values, focusable hint, unit tests

* Normalize server version suffixes and cache the capability matrix

* Add capability matrix strings to the translation template

* Treat an unknown (null/empty) server version as supported to avoid a TypeError

* Cover the capability helpers in the installer coverage suite

---------

Co-authored-by: TheWitness <copilot@users.noreply.github.com>
2026-10-05 20:16:01 -04:00
TheWitnessandTheWitness 1c96e16a3f support: recommend supported DB releases and fix MariaDB detection (#8186)
* support: recommend supported DB releases and fix MariaDB detection

- Update the database version recommendation to the supported release streams (MariaDB 10.5+, MySQL 8.0+, e.g. the defaults on RHEL 9) and make the recommended '>=' threshold database-aware instead of a flat 5.6.
- Fix MariaDB being mis-detected as MySQL when the version suffix capitalization differs: use case-insensitive matching (stripos/str_ireplace) in get_mysql_info() and the connection setup. This drives the '%s Tuning' header and all MySQL/MariaDB branching on the Technical Support page.
- Remove dead code that special-cased MySQL < 8.0 (now unsupported): the '(MySQL && < 8.0) || MariaDB' guards in support.php and lib/utility.php collapse to just 'MariaDB'.

* support: reference Rocky Linux 9 instead of RHEL 9 in DB recommendation

* support: change RHEL font-path comment to Rocky

* docs: update System Requirements and DB recommendation for 1.3.x

- README: raise minimums (develop: MariaDB 10.11+, MySQL 8.4+, PHP 8.3+; 1.2.x column: MariaDB 10.5+, MySQL 8.0+, PHP 8.2+, RRDtool 1.7+), set Net-SNMP 5.9+ floor, mark php-snmp fully supported, and note upcoming PHP 8.6 support speeding up Script/Script Server collection.
- Bump the develop DB recommendation to MariaDB 10.11+/MySQL 8.4+ to match the 1.3.x minimum.

---------

Co-authored-by: TheWitness <TheWitness@users.noreply.github.com>
2026-10-05 19:50:42 -04:00
TheWitness 474f00c6e7 support: drop php-snmp uninstall warning from Technical Support page (#8182)
* support: drop php-snmp uninstall warning from Technical Support page

The PHP SNMP row on the Technical Support page told users that, to use
SNMPv3, they must remove php-snmp and switch to the Net-SNMP toolset.
Cacti now selectively uses the Net-SNMP binaries where needed (SNMPv3 with
advanced ciphers, IPv6, bulkwalk, hex output) and keeps php-snmp for the
rest, so uninstalling it is unnecessary. Report the extension as simply
Installed.

* docs: mandate cacti.pot update for any i18n string change

develop copilot-instructions only said to wrap strings with __(); it did not mention the translation template. Make it explicit that adding, changing, or removing a translatable string MUST update locales/po/cacti.pot in the same PR, and only that file.

* i18n: update cacti.pot for removed php-snmp SNMPv3 warning

support.php no longer emits the long php-snmp uninstall warning; it now prints __('Installed.'). Replace the removed msgid in locales/po/cacti.pot with the new 'Installed.' string. Only cacti.pot is touched.
2026-10-05 10:39:41 -04:00
TheWitness 41e6d9e033 security: consolidate verified GHSA fixes for develop (batch 4) (#8145)
* security: consolidate verified GHSA fixes for develop (batch 4)

Develop counterparts of the 1.2.x batch-4 fixes in #8144, re-verified against
current develop HEAD.

- GHSA-4rmr-wvjq-qxc2: include/auth.php Basic Auth and guest branches fall
  through to the per-page realm check instead of returning early.
- GHSA-j67j-wpm4-9g3x: the pre-dispatch update_policy branch in user_admin.php
  and user_group_admin.php requires a CSRF-token POST. The denylist -> allowlist
  redesign is tracked for 1.3 in #8143.
- GHSA-2p3x-f5jm-rg6p: the View-Graphs -> poller RCE chain is broken by the
  realm check (4rmr), the update_policy guard (j67j) and shell-free webhits (x5pw).
- GHSA-x5pw-cg7j-mj4r: scripts/webhits.pl runs wc through a shell-free list-form open.
- GHSA-9737-rqh3-h7fh: names interpolated into raise_message() now use __esc()
  across the UI; URL- and HTML-bearing messages are excluded.
- GHSA-9x9h-2577-9w86: the colordropdown input is built as a node and the label
  is no longer round-tripped through parseHTML (the list item already used
  createTextNode on develop).
- GHSA-h96j-8xhc-2p3w: remote_agent.php authorizes on $_SERVER['REMOTE_ADDR'],
  not get_client_addr(), which honours client-settable proxy headers.

Regression guards under tests/Unit/Security/{Auth,Csrf,Xss,ShellInjection}.
php -l, check-changelog.py and the sink/architectural baselines all pass.

* chore: reference PR #8145 on the batch-4 1.3.0-dev CHANGELOG entries

* security: resolve develop merge - keep id-only xmlerror unescaped (matches #8141 h745 test)

* security(GHSA-j67j): use REQUEST_METHOD POST guard instead of raw \ (hardening-pattern-guard)

* security(GHSA-9737): fix review findings - drop double-encoding in __esc, escape missed name sinks, correct plugins format-arg count
2026-10-02 13:10:42 -04:00
TheWitnessandTheWitness 3ab4c69fb7 PHPStan Level 8 - Phase 1 Conversion (#8135)
* PHPStan Level 8 - Phase 1 Conversion

Reduces the real (no-baseline) PHPStan level 8 error count from ~2,724 to 425
and regenerates phpstan-baseline.neon accordingly (8,941 -> 1,921 lines).

Core type-safety changes
- lib/database.php: narrow db_fetch_row()/db_fetch_row_prepared() to return
  array (was bool|array) and db_fetch_assoc()/db_fetch_assoc_prepared() to
  return array (was mixed); the _prepared workers coerce the connection-failure
  path to an empty array so the declared type is honest. empty()/cacti_sizeof()
  checks are unaffected.
- lib/database.php: narrow $db_conn guards from is_object() to instanceof PDO in
  the transaction/quote/insert-id helpers so the PDO calls resolve.
- lib/mib_cache.php: the fluent MibCache methods mib()/object()/table()/row()
  now return self instead of a bare object so chained calls type-check.

Type-safety casts and guards (mechanical, behaviour-preserving)
- Cast string|false/|null builtin results feeding string parameters
  (json_decode, base64_encode, trim, htmle, preg_replace, explode, etc.).
- Cast int|string / int|false values feeding int id/pid parameters.
- Guard resource|false fopen()/popen() handles before fwrite/fclose/fread, and
  wrap foreach over array|false/list|false results with `?: []`.

Genuine bugs found and fixed
- cli/add_tree.php / lib/api_tree.php: site tree nodes could not be created via
  the CLI - the --site-id option was never parsed, $nodeTypes had no 'site'
  entry (passing null to api_tree_item_save(int $type) -> TypeError), and
  api_tree_item_save() never persisted site_id. All three fixed.
- tree.php: leaves_exist() is typed : int but returned db_fetch_assoc_prepared()
  (an array of rows) for a SELECT COUNT(*); now uses db_fetch_cell_prepared()
  and returns the scalar count.
- lib/mib_cache.php: $entries_per_object was a float (division / ceil) used as
  an array key (PHP 8.1 implicit float-to-int key deprecation); now cast to int.

Config
- .phpstan.neon: add notIdentical.alwaysTrue and booleanAnd.alwaysFalse to the
  existing always-true/false ignore family (same "PHPStan gets confused"
  dynamic-constant cause already covered by identical.alwaysTrue,
  notEqual.alwaysTrue, booleanAnd.leftAlwaysTrue, etc.).
- phpstan-baseline.neon: regenerated; the remaining 425 entries are the
  untouched long tail for Phase 2.

* Remove redundant @phpstan-ignore comments

Follow-up cleanup for the level 8 Phase 1 work. Removes 14 inline
@phpstan-ignore comments that no longer suppress any reported error:

- cli/repair_database.php: `@phpstan-ignore booleanAnd.alwaysFalse` is now
  covered by the global booleanAnd.alwaysFalse ignore added to .phpstan.neon.
- 13 others (host.php, include/global.php, include/session.php,
  lib/api_automation.php x2, lib/functions.php x2, lib/html_utility.php x2,
  lib/installer.php, lib/package.php, lib/reports.php, lib/rrd.php) no longer
  match any reported error after the type-safety fixes (e.g. the
  db_fetch_row_prepared() return-type narrowing removed the offset-assign
  errors the api_automation ignores were suppressing).

Verified with reportUnmatchedIgnoredErrors enabled: 0 unmatched ignores
remain and the full level 8 run still reports 0 errors.

* ci: satisfy validator ratchet and refresh security sink baselines

- lib/api_tree.php: give the new tree-item site_id a real numeric
  constraint ('^[-0-9]+$', matching html_reports.php) instead of an
  empty regex, so the validator constraint ratchet passes without
  bumping its baseline.
- tests/security/baselines: refresh the three sink/hotspot signatures
  whose code text changed from the (string) casts added in this branch
  (lib/poller.php setsid, cli/rrdresize.php json_encode, lib/import.php
  simplexml_load_string).

* ci(js): allow DOMPurify 3.4.16 and update sync_js pin test

The dependabot bump (#8134) moved package.json/package-lock.json to
DOMPurify 3.4.16 on develop but left tests/js/sync_js.test.mjs pinned to
3.4.15, so the PR merge commit fails the 'DOMPurify is pinned' contract.
Bring package.json/package-lock.json to 3.4.16 (matching develop) and
update the pin test to expect 3.4.16.

* test: update sql.php null-handling assertion for the (string) cast

This branch changed scripts/sql.php from trim(\ ?? '') to
trim((string) \) (the phpstan-safe form that coerces both null and
false from shell_exec()). Update SqlScriptsTest's null-return assertion
to match the new cast instead of the removed '?? ''.

* fix: address Copilot review - ownership IDs, fopen guards, mib_cache bound

- chown()/chgrp(): pass integer UID/GID from fileowner()/filegroup()
  (guarding the false lookup) instead of string-casting them, which made
  them resolve account/group names like '1001' and fail. Covers
  lib/api_device.php, lib/boost.php and poller_maintenance.php (x2).
- fopen() failure now short-circuits instead of reporting success:
  lib/package.php returns false, lib/clog_webapi.php and utilities.php
  render an error, and snmpagent_mibcachechild.php skips the cache write
  and sentinel unlink so a concurrent writer's lock is preserved.
- lib/mib_cache.php: keep the float quotient as the loop bound and cast
  only the array offset, so a non-even entries/columns split no longer
  truncates the loop and drops a cached row.

* revert: keep db_fetch_* returning false on error; baseline Level 8 instead

Per review, restoring the intentional fail-safe: db_fetch_row[_prepared]()
return bool|array and db_fetch_assoc[_prepared]() return mixed again, so a
genuine SQL error (not just a missing connection) is signalled as false and
the === false checks in cdef_is_in_use(), boost_process_* and aggregate.php
work as before. Dropped the is_array() ? : [] coercion.

Level 8 stays green by regenerating phpstan-baseline.neon to capture the
re-introduced bool|array/mixed call-site errors (the ~1,850 the narrowing
had eliminated). Tightening those callers to drop them from the baseline is
Phase 2 work.

---------

Co-authored-by: TheWitness <copilot@users.noreply.github.com>
2026-10-02 10:08:56 -04:00
Thomas VincentandTheWitness 7c5e4c102a feat(support): consolidate diagnostics, lockout CSRF, process-table hook, and safe-triage (#7514)
* feat(support): add redaction toggle and recent-log panel

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test: cover support safe triage

Unit-test the redaction helper, severity log tail and environment table, and add a Docker probe that the redacted report masks the RSA fingerprint and hides the database host and password.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): escape rsa fingerprint and default unknown poller type

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* ci: refresh security baselines

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): redact compressed IPv6 addresses

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* ci: refresh security baselines

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* ci: skip tests tree in hardening pattern guard

Test fixtures assign request superglobals to exercise product code; the guard only protects product code.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): drop redundant isset flagged by phpstan

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* feat(support): guard snmpget path before executing

Reject a null byte and require a regular executable file for path_snmpget
so a misconfigured path cannot throw a ValueError or match a directory.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* ci: refresh security baselines for snmpget path guard

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): redact FQDNs before the node name and stop truncating tool output

Masking the node name first could leave a domain suffix unmasked when
the name was a prefix of an FQDN, and strip_tags() on installed SNMP
output dropped legitimate angle-bracket content instead of just
masking it. Also tighten the redact toggle to a strict '1' match,
carry it through page-refresh URLs, and correct the diagnostics report
comment to describe what actually gets masked.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): guard poller type lookup, log stats, and binary path checks

Fall back to an "Unknown" label when poller_type doesn't match a known
poller instead of an undefined-index warning, suppress warnings from
filesize()/fopen() if the log file disappears between the caller's
check and the open, and require is_file() plus a null-byte guard on
the required-binaries version check (matches the snmpget check next
to it).

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* docs(tests): align triage probe comments with actual assertions

The header comments claimed the unredacted report exposes the DB host
and password, but the probe only ever asserts the RSA fingerprint;
DB credentials are checked for absence when present, not required to
appear unmasked. Correct the wording in both files.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): require POST + CSRF token for maintenance lockout, compare-and-set

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): require a valid expected state for lockout compare-and-set

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(security): refresh sink/hotspot baselines for upstream line shifts

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): clamp page offset, quote SQL literals, suppress lockout URL state

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test: cover support lockout csrf guard

Exercise the POST-only guard and compare-and-set branches, and add a Docker probe that a GET or tokenless POST cannot change the lockout state.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(support): guard lockout probe extraction and correct probe scope note

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* ci: refresh security baselines

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* ci: skip tests tree in hardening pattern guard

Test fixtures assign request superglobals to exercise product code; the guard only protects product code.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): keep lockout e2e health poll alive under pipefail

Tolerate grep returning non-zero before the Health field appears so the
poll loop waits instead of exiting the script.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(support): add integration coverage for the lockout compare-and-set

The Unit test cannot reach the "currently locked" branch (forced reads
return the PHP_TESTING default) and the e2e probe deliberately never
locks the system, so the real read/write round trip against
cacti_lockout_status has no coverage. Add a fast integration test that
drives the lock, a stale-expected rejection, and the unlock against a
real database, skipping gracefully when none is reachable.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(support): match the page-clamp assertion whitespace-tolerantly

Whitespace-exact substr_count() breaks on reformatting; the regex enforces
the same guard without depending on exact spacing.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): harden the lockout e2e probe's auth and cookie-jar handling

Assert a CSRF token was extracted and the session actually authenticated
before running the lockout checks, otherwise a failed login still passes.
Also handle tempnam() failure and clean up the cookie jar on every exit
path via a shutdown handler.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* feat(support): add diagnostics export and environment checks

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test: cover support diagnostics export

Unit-test the environment table and report redaction, and add a Docker probe that checks the report never leaks the database host, password or full RSA fingerprint.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): guard null snmp version and copy-status styling

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* ci: refresh security baselines

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): keep diagnostics textarea visible on copy failure and report real extension load state

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* ci: refresh security baselines

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): verify PHP extensions in both cli and web contexts

show_tech_environment() only checked utility_php_verify_extensions()'s
web flag, which seeds CLI-only extensions like pcntl as satisfied
without checking whether they're actually loaded. Shell out to
cli_check.php for the real CLI state and combine it with the web
state the same way lib/installer.php does, so status reflects reality
in both directions.

Also guard the source-extraction helpers in SupportDiagnosticsTest and
the e2e probe against a moved/unreadable support.php instead of
letting strpos(false, ...)/eval() fail confusingly.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): require POST + CSRF token for maintenance lockout, compare-and-set

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* refactor(support): register process tables via support_process_tables hook

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): guard non-array hook result and empty process-table set

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): cast poller_interval to int in SQL and validate hook entry types

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(security): refresh sink/hotspot baselines for upstream line shifts

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): reuse forced admin lookup and coerce expected state

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test: cover support process-table hook

Verify the hook drops malformed plugin definitions and keeps valid ones, and add a Docker probe that the hook returns well-formed tables against a real database.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(support): guard hook extraction and tolerate empty health probe

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* ci: refresh security baselines

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): escape plugin-contributed process-table cells

Plugins can now supply the process-table SELECT fragments via the
support_process_tables hook, so escape the rendered cell values, and
install the e2e cleanup trap before backing up config.php.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* ci: refresh security baselines for support.php line shift

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): use form_selectable_ecell for process rows and cast pid in row id

Plugin-contributed process-table values were only escaped via manual
html_escape() calls, and the row id was built from an unsanitized pid;
switch to the file's existing form_selectable_ecell() helper and cast
pid to int before it goes into the id attribute.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(support): harden hook-call rewrite and narrow validation comment

Replace the exact-string str_replace() with a regex plus a match-count
assertion so the probe fails loudly instead of silently no-op'ing if
support_process_tables() formatting drifts, and correct the header
comment's claim that malformed definitions can't corrupt the UNION --
the validation only checks types, not SQL validity.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(support): make e2e hook extraction regex whitespace-tolerant

The extraction pattern required exact spacing around the function
signature; match flexible whitespace instead and fail loudly if
preg_match doesn't return exactly one match.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(support): add integration coverage for the process tables SQL path

Unit tests eval() support_process_tables() with the plugin hook stubbed
and never touch a database; the e2e Docker probe calls the same function
directly but never builds or executes the UNION show_cacti_processes()
runs. Add a fast, DB-only integration test that executes the real query
against a live schema, skipping gracefully when no database is reachable.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): harden process table hook contracts

* docs: add changelog entry

* style: satisfy support hook fixer rules

* fix(support): reconcile escaping contract and diagnostics test after merge

tech_env_status() now escapes its $text argument (safe-triage's design,
tested by SupportSafeTriageTest); strip the now-redundant html_escape()
calls at its call sites in show_tech_environment() to avoid double
encoding. Update SupportDiagnosticsTest's source-extraction marker and
eval() inputs to match the merged, redact-toggle-aware report block from
safe-triage. Refresh the sink inventory baseline for the resulting line
shift.

* fix(support): escape the PHP uname value on both redact paths

Hostnames and kernel strings can carry markup, and support_redact() itself substitutes <host>, so redact first and escape the result either way.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(support): locate the diagnostics report block by regex, not literal

The $snmp_line assignment became a conditional and the literal start marker stopped matching, aborting the probe before it built a report.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* docs: append the process tables entry to the feature block

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <thewitness@cacti.net>
2026-08-05 10:42:46 -04:00
Thomas VincentandTheWitness 15c34d94fe fix(support): repair mikrotik branch, guard task filter, escape table metadata (#7350)
* fix(support): repair mikrotik branch, guard task filter, escape table metadata

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(support): single-quote SQL string literals for ANSI_QUOTES safety

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(security): refresh sink/hotspot baselines for upstream line shifts

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <thewitness@cacti.net>
2026-07-24 21:19:26 -04:00
Thomas Vincent 02ff0ae377 Show php-snmp bypass state on Technical Support page (#7266)
* Show php-snmp bypass state on Technical Support page

Ref #6669

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* Name include/config.php in the php-snmp status messages

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
2026-07-12 20:08:28 -04:00
Nguyễn Công Tú 161355b62e fix: [Security] Cross-Site Scripting (XSS) stored (#7147) 2026-05-13 15:36:32 -04:00
3e1dc3c886 fix: replace strtolower/strtoupper with locale-independent wrappers (#6717)
* cleanup: remove unreachable defensive error logs in aggregate graph item validation

* fix: replace strtolower/strtoupper with locale-independent wrappers

PHP 8.5 deprecates locale-sensitive strtolower() and strtoupper().
Add cacti_strtolower() and cacti_strtoupper() wrappers that use
mb_strtolower/mb_strtoupper with explicit UTF-8 encoding, then
replace all 185 call sites across 65 files.

Existing mb_strtolower() calls (email normalization) are left as-is
since they already specify encoding explicitly.

Includes 18 Pest tests covering ASCII, UTF-8, protocol names, config
values, hex strings, NaN detection, and file extension patterns.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix: correct docblock references and month_shift() strpos check

Fix docblocks to reference strtolower()/strtoupper() (the deprecated
PHP builtins) instead of the wrapper names. Fix month_shift() to use
strpos() !== false instead of > 0 so 'month' at position 0 is matched.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* chore: drop unrelated lib/api_aggregate changes

Keep PR scope focused on the issue for this branch.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: TheWitness <thewitness@cacti.net>
2026-03-05 19:51:02 -05:00
Thomas VincentandTheWitness fcbcbdd1d7 refactor: replace strpos() boolean checks with str_contains/str_starts_with (#6645)
* refactor: replace strpos() boolean checks with str_contains/str_starts_with

Completes the PHP 8.x string function migration started in lib/.
Converts remaining legacy patterns across 81 files:

- strpos($x, $y) !== false → str_contains($x, $y)
- strpos($x, $y) === false → !str_contains($x, $y)
- strpos($x, $y) != false  → str_contains($x, $y)
- bare if (strpos($x, $y)) → if (str_contains($x, $y))
- substr($x, 0, strlen($y)) == $y → str_starts_with($x, $y)

Intentionally preserves strpos() calls that use the return value as
an integer offset:
- user_admin.php / user_group_admin.php (4 calls, ternary for position)
- auth_profile.php (2 calls, offset for substr); guards fixed from
  bare if ($pos) to if ($pos !== false)

Behavior fix: ss_esxi_vhosts.php:55 bare strpos() missed position-0
matches; str_contains() now correctly detects 'not installed' at any
position. Adjacent line already used str_contains().

Ref: https://github.com/Cacti/cacti/issues/6641

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix: correct dead-code elseif in plugin_display_compat() version comparison

The if/elseif chain in plugin_display_compat() checked >=, >=, >, <
— the second >= was unreachable dead code. Corrected to <= to complete
the operator set (>=, <=, >, <).

Without this fix, <= constraints (e.g. "<=1.2") fell through to the <
branch and were rendered as "< =1.2" instead of "<= 1.2".

This pre-existing bug was exposed when converting strpos() to
str_contains(), which made PHPStan detect the always-false condition.

Ref: https://github.com/Cacti/cacti/issues/6641

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix: add limit to explode('=') in CLI argument parsers

17 CLI scripts used explode('=', $parameter) without a limit of 2,
silently truncating values containing = (e.g. --note=a=b parsed as
$value='a' instead of 'a=b'). The other 40 CLI scripts already had
the correct limit.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <thewitness@cacti.net>
2026-02-25 11:38:59 -05:00
TheWitness 27919c50d7 Updating Copyrights to 2026 (#6578) 2026-01-28 16:11:10 -05:00
TheWitnessandCopilot b993471579 Fix #6539 - Allow Standard Cacti Log Files to be Rotated on Demand,PHPdoc, and Typing (#6540)
* Fix #6539 - Allow Standard Cacti Log Files to be Rotated on Demand from the Cacti UI

* QA: php-cs-fixer updates and documentation for lib/database.php

* QA: Update .gitignore for composer files

* QA: Update .gitignore for composer files

* QA: Back off .gitignore change its duplicated

* QA: Fix typing of db_has_permissions

* QA: Fixing typing issue in db_format_index_create

* Update lib/clog_webapi.php

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* QA: Fix additional code issues

* QA: Applying more defaults to add device

* QA: Fix at the database layer

* QA: Fixes based upon automated testing

* QA: Fix at the database layer

* QA: After new SQL checking

* QA: Skip MacTrack oui database download warnings

* QA: Fixing type issue

* QA: Recommendation from Copilot

* QA: Recommendation from Copilot

* QA: Recommendation from Copilot

* QA: Recommendation from Copilot

* QA: Some minor changes to avoid errors in testing

* QA: Unused variable

* QA: Recommendation from Copilot

* QA: Recommendation from Copilot

* QA: Recommendation from Copilot

* QA: Minor introduced code defect

* QA: Adding some unifying space around concatination

* QA: Consistent comments and new function alias'

* QA: Multi-line comment corrections

* QA: Fix SQL Style

* QA: Missed one function alias

* QA: PHPStan Level 2 and PHPDoc fixes

* QA: PHPStan Level 2 and PHPDoc Fixes

* QA: PHPStan Level 6 Fixes

* QA: Fix lib/xml.php to PHPStan Level 6

* QA: Wrong grep -v

* PHPStan Level 6 for lib/vdef.php

* PHPStan Level 8 for lib/time.php

* QA: Raise PHPStan to Level 6 for lib/database.php

* QA: Remove @deprecated tag from grv()

* QA: Switch to htmle() alias over html_escape()

* QA: More addressing PHPStan issues at Level 6

* QA: Change recommended by Copilot for Readability

* QA: More PHPStan fixes

* QA: More PHPStan fixes

* QA: More PHPStan fixes for lib/utility.php

* QA: More PHPStan fixes at Level 6

* QA: Raise PHPStan to Level 6 More Functions

* QA: Raise PHPStan to Level 6 More Functions

* QA: Raise PHPStan to Level 6 More Functions

* QA: Raise PHPStan to Level 6 More Functions

* QA: Raise PHPStan to Level 6 More Functions

* QA: More PHPStan fixes at Level 6

* QA: Raise PHPStan to Level 6 More Functions

* QA: Raise PHPStan to Level 6 More Functions

* QA: More PHPStan fixes at Level 6

* QA: More PHPStan fixes at Level 6

* QA: Raise PHPStan to Level 6 More Functions

* QA: Raise PHPStan to Level 6 More Functions

* QA: More PHPStan fixes at Level 6

* QA: Raise PHPStan to Level 6 More Functions

* QA: Raise PHPStan to Level 6 More Functions

* QA: More PHPStan fixes at Level 6

* QA: Raise PHPStan to Level 6 More Functions

* QA: Raise PHPStan to Level 6 More Functions

* QA: More PHPStan fixes at Level 6

* QA: More PHPStan fixes at Level 6

* QA: More PHPStan fixes at Level 6

* QA: Raise PHPStan to Level 6 More Functions

* QA: More PHPStan fixes at Level 6

* QA: Some phpseclib3 fixups to update to latest

* QA: More fixups for graphing for magic strings

* QA: More PHPStan fixes at Level 6

* QA: Fixing order string type on get_allowed_graphs()

* QA: Fixing improper use of print

* QA: Optimization of color_templates

* QA: Copilot recommendation

* QA: Copilot recommendation

* QA: Copilot recommendation

* QA: Copilot recommendation

* QA: Copilot recommendation

* QA: Copilot recommendation

* QA: Copilot recommendation

* QA: Copilot recommendation

* QA: Raise PHPStan to Level 6 More Functions

* QA: Issues insalling Cacti

* QA: Issues insalling Cacti

* QA: Issues insalling Cacti

* QA: Issues insalling Cacti

* QA: Issues insalling Cacti

* QA: Issues testing Cacti

* QA: Copilot recommendation

* QA: More PHPStan fixes at Level 6

* QA: More PHPStan fixes at Level 6

* QA: More PHPStan fixes at Level 6

* QA: More PHPStan fixes at Level 6

* QA: More PHPStan fixes at Level 6

* QA: Installer failing

* Undo ownership changes to remove tar errors

* QA: Updates after php-cs-fixer

* QA: Adding code checks to syntax checking

* QA Change syntax flow language

* QA: Reduce the number of cures

* QA: Use sequentional option

* Change runner to self-hosted for check job

* Fix typo in OS version in workflow file

* Add Git installation step in workflow

Added step to install Git if not already installed.

* Add '-y' flag to apt-get install and update commands

Updated apt-get commands to include '-y' for automatic confirmation.

* Change workflow OS version to 'ubuntu-latest'

Updated the workflow to use 'ubuntu-latest' instead of 'ubuntu:latest' and modified the 'runs-on' configuration.

* Remove sequential option from phpcsfixer script

* Remove PHPCS fixer step from workflow

Removed PHP coding standards check from workflow.

* Move code checks to before plugins

Moving these core checks to before the plugins are installed as we really want to check only the base Cacti here.

* Add Composer validation and caching to start of workflow

* QA: Addressing PHPStan additional

* QA: Restore composer lock file

* QA: Addressing PHPStan additional

* QA: Addressing PHPStan additional

* QA: Complete LDAP Project

* QA: php-cs-fixer doing it's thing

* QA: Syntax is already happening in PHPStan

* QA: The md5 function no longer exists

* QA: Update after ldap changes

* QA: Undo that last password hack

* QA: Attempting to switch to MariaDB 11.8

* QA: Attempting to switch to MariaDB 11.8

* QA: Resolving some issues with PHP8.4

* QA: Resolving some issues with PHP8.4

* QA: Add PHP8.5 to the matrix

* QA: Removing PHP8.5 due to dependency issues

* QA: Add the DB version to the testing output

* QA: Switch back to MySQL for the moment

* QA: More fidelity in reporting

* QA: The pipe must be mixed

* QA: Moving audit_schema.php changes from 1.2.x

* QA: Moving audit_schema.php changes from 1.2.x

* QA: Restore mysql monitoring

* QA: php-cs-fixer issues

* QA: Attempt to roll back to MariaDB 10.6

* QA: Attempt to fix check_all_pages.sh

* QA: Make installer functional again

* QA: Fix installer php-cs-fixer issues

* QA: Type to a string

* QA: Get the database version correctly

* QA: Fix issue with reports in check_all_pages.sh

* QA: Check the server version in the right place

* Feature: Support SHA256 as a new hash for passwords

* QA: Function definition and return typing audit

* QA: Refinement of form types

* QA: Refinement of form types

* QA: Consistency of comments

* QA: Issues with php-cs-fixer and more comments

* QA: More typing issues

* QA: php-cs-fixer on merge conflict resolution

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-25 10:13:56 -05:00
TheWitness dd12bfe689 QA: Fixing additional files at phpstan level 3 2025-11-19 21:44:31 -05:00
TheWitness b9334a15d9 QA: Updates for files for php-cs-fixer and some php-doc changes 2025-11-18 21:01:15 -05:00
TheWitness ff8b830653 QA: Make the database processlist work with older db versions 2025-08-18 07:29:30 -04:00
TheWitness 63f7457371 QA: More compatibility issues with MariaDB 2025-08-17 22:39:38 -04:00
TheWitness e978f8f49d QA: Wrong function 2025-08-17 22:21:35 -04:00
TheWitness 77d7694e54 QA: More checks and changes 2025-08-17 21:23:13 -04:00
TheWitness ebf9aff7ad QA: Work with older MariaDB versions 2025-08-17 21:03:24 -04:00
TheWitness 8b9c29708c QA: Finishing up buttons 2025-07-13 12:58:53 -04:00
TheWitness ac0c1c5c45 Switch from include to require 2025-04-03 14:37:02 -04:00
TheWitness 685d4b9357 Start addressing PHPStan Issues 2025-03-23 14:09:11 -04:00
TheWitness d2624514cc Restore parts of lib/rrd.php move/rename a function 2025-03-23 10:23:11 -04:00
TheWitness e5c4015e0e QA: Remove most references to $config
This removes most entries to $config in the base code.  A few new constants were defined to achieve this:

* CACTI_CONNECTION - The status of the current connection
* CACTI_CSRF_SECRET - The path to the csrf secret file
* CACTI_PHP_SNMP - True if php-snmp is installed
* CACTI_WHITELIST - The path to the Cacti Whitelist file if defined

I also moved several $config['poller_id'] to the existing POLLER_ID and move a number of $config['is_web'] to the existing CACTI_WEB constants.

There remain a few artifacts in the code.  They will be handled in a separate commit.
2025-03-22 16:48:59 -04:00
TheWitness 2c779273f9 Copyright Updates and PHP-CS-Fixer updates 2025-03-09 14:34:19 -04:00
TheWitness d68942c84f QA: Remove name space collisions causing vscode issues 2025-03-08 17:54:26 -05:00
TheWitness 38b4167b9e QA; Revert the last change. Need more coffee 2025-01-03 07:56:08 -05:00
TheWitness e58a84d515 QA: No three bars on Background Process and Queires 2025-01-03 07:52:45 -05:00
TheWitness 26abeaae79 QA: #1773 - Light Redesign to Allow All Primary Admin Logins 2024-12-27 13:40:11 -05:00
TheWitness 773a5a7c6c QA: Security audit sweep results 2024-12-24 11:56:28 -05:00
TheWitness be1b1200ce Fix: #1773 - Lock Cacti Install
* This was fixed by introducing a setting to lock the Cacti install to a single user mode from the Support > General page, and only for the primary administrator.
2024-12-22 12:30:37 -05:00
TheWitness 366359c42b QA: Migrate support.php to Filter Class and Prepared Statements 2024-12-20 12:00:51 -05:00
TheWitness 3bada47208 QA: Phase 1 of filter cleanup prior to migration
* Introduce a new wrapper function for showing the show/hide column indicator
* Migrate all Core packages to use that new wrapper function
* Migrate pages to have JavaScript show immediately below the form object.
* Correct some indentation issues
2024-12-16 13:01:17 -05:00
TheWitness afcd847639 Revert "QA: Don't use CRLF. Use LF"
This reverts commit 60d42af89c.
2024-12-11 22:47:42 -05:00
TheWitness 60d42af89c QA: Don't use CRLF. Use LF 2024-12-11 22:42:45 -05:00
Jimmy Conner 7367f76c5a Missing global in support 2024-12-09 02:46:34 -06:00
TheWitness e183945b2a QA: Add Clear button as a 1 second refresh is hard to change 2024-11-27 14:59:32 -05:00
TheWitness af73c04fc2 QA: The timer needed to be reset 2024-11-27 14:50:46 -05:00
TheWitness 026ca27bd8 QA: Increase precision to 1 second 2024-11-27 14:45:00 -05:00
TheWitness de57e21e8d QA: Convert the Settings Search to a div based table
* We want most things as divs converting one more page
* Add some CSS to pages that lack it for jQueryUI
* Remove a duplicate onChange attribute.
2024-11-26 16:05:52 -05:00
TheWitness f9bc09bf43 feature: Add years to get_daysfromtime function
* Added this part and then corrected some soft-tab issues
* Make the support page on timeout more readable
2024-11-14 20:58:33 -05:00
TheWitness b937f67456 Fix #5866 - Add database to database permissions structure 2024-11-09 13:01:02 -05:00
TheWitness ba49b776df QA: Fix some visual issues with Technical Support ChangeLog 2024-11-06 23:23:15 -05:00
TheWitness f1b8076c85 QA: Add MacTrack and ServCheck background processes 2024-10-16 13:24:07 -04:00
TheWitness f92e3172e3 Minor QA on #5861 2024-10-16 11:19:09 -04:00
TheWitness 6a283bb569 Fixing #5861 - Add Processes and Queries to Tech Support
* In Cacti Utilities, be able to view the MariaDB/MySQL processeslist and active background tasks
* Restructuring this page to separate the various calls into functions for readability.
2024-10-16 10:54:05 -04:00
TheWitness bd30bf0ffe QA: Updating Copyrights to 2024 2024-03-16 04:49:30 +05:30
Jing Chen 6f2801456f Show wrong number if use __() + number_format_i18n and value > 1000 (#5669) (#5674)
* Show wrong number if value larger than 1000 and use __() + number_format_i18n
* Update CHANGELOG for PR#5669
2024-02-20 20:26:06 -05:00
TheWitness 75d704edf4 QA: Remove old stub function name documentation 2023-11-12 22:09:20 -05:00