11 Commits
Author SHA1 Message Date
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 Vincent 79a9ae0351 build: raise the 1.3 floor to PHP 8.3 (#7939)
* build: raise the 1.3 floor to PHP 8.3

RHEL 10 ships 8.3 in AppStream and dropped modularity, so an 8.4 floor would
put every RHEL, Alma and Rocky 10 install on Remi. Ubuntu 24.04 is 8.3 as
well, which makes it the lowest common denominator of the current LTS fleet.

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

* docs: raise the documented PHP floor to 8.3

The 1.2.x column keeps 8.1, which still matches that branch's composer constraint.

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

* ci: run process lock coverage on PHP 8.3

* fix: finish PHP 8.3 floor cleanup

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

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
2026-09-06 08:44:40 -07:00
Thomas Vincent ac0b2c9515 Fix confirmed poller, database, automation, and UI defects (#7861)
* issue#7024: do not delete still-running poller_time rows on cycle start

The overrun path deleted every poller_time row for the poller, including the
in-flight ones it had just counted, so overrunning processes lost their
tracking. Restrict the delete to completed rows.

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

* issue#7028: restore identifier and connection safety in the db layer

_db_replace interpolated caller-supplied column keys as backtick identifiers
without escaping, and db_commit_transaction checked @@in_transaction on the
default connection rather than the one passed in. Both were correct on 1.2.x
and regressed on develop.

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

* issue#7341: size the CSV export maxrows to the requested span

The export hardcoded --maxrows=10000, truncating wide date ranges regardless
of the data source profile step.

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

* issue#7421: offset automation_get_next_host through the 32-bit integer

The hand-rolled octet walk subtracted the wrong magnitude per octet and
emitted out-of-range octets for ranges wider than a /16.

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

* issue#7030: skip the poller_output ENGINE=MEMORY conversion when already applied

The output-table refresh ran ALTER TABLE poller_output ENGINE=MEMORY every
cycle even though the swapped-in copy already inherits the engine, adding a
metadata-locking DDL to the hot path. Probe the current engine and convert
only when needed.

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

* issue#7342: prefer snmpEngineTime only when it covers system uptime

update_system_mibs preferred snmpEngineTime (x100) over sysUpTime whenever it
was present, so an SNMP engine that restarts independently of the system (for
example OpenBSD snmpd) made the stored uptime drop, which reads as a reboot
and forces a perpetual reindex with mass 'U' results. Capture both values and
use snmpEngineTime only when it is at least the system uptime, which still
covers the 32-bit sysUpTime wrap.

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

* issue#7403: scale lmsensors readings in the get path like the query path

The get path returned the raw milli-unit SNMP counter while the query path
divided voltage and temperature by 1000 (and corrected negative voltages), so
a get gave values 1000x too large. Apply the same scaling before returning.

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

* issue#7029: propagate the reconnected handle back to the caller

db_check_reconnect() closed the dead connection, opened a new one, and
returned true without giving the new handle back, so the db_execute_prepared
retry ran its query against the connection that was just closed. Take $db_conn
by reference and assign the fresh handle; the one caller that passed a literal
false now passes a variable.

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

* test: refresh sink inventory baseline

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

* test: refresh architectural hotspots baseline

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

* issue#7474: return valid after correcting the theme to selected_theme

is_valid_theme() corrected an invalid theme to selected_theme but left $valid
false, so callers saw the theme as invalid even though it had been fixed.

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

* issue#7462: allow SELECT aliases as sortable automation columns

site_name and host_template_name are aliases (s.name AS site_name), valid in
ORDER BY but not real columns, so api_automation_column_exists() rejected them
and the site-name sort silently failed.

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

* issue#7456: bind the OS value in the automation OS filter

The OS filter built 'os = ?' but bound the network value, so filtering by OS
matched on the wrong input.

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

* issue#7491: filter host_template_id against its own column

html_make_device_where() compared h.location to the host_template_id value
instead of h.host_template_id.

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

* issue#7479: apply the hostname and description filters in get_hosts

The REST get_hosts() honored host_id/poller/site/template/location but ignored
the hostname and description filters its callers pass; add them as bound LIKE.

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

* issue#7475: authorize a direct client-IP poller match before the hostname guard

A poller configured by IP with no hostname-based pollers was rejected because
the empty-hostname guard ran before the direct-match check, even though the
client address exactly matched a poller's configured address.

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

* Guard two divisors that PHP 8 makes fatal

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

* docs: consolidate functional fix changelog

* test: cover consolidated functional fixes

* docs: identify consolidated functional fixes

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
2026-09-01 21:01:28 -07:00
Thomas Vincent a8e1afba73 Refuse to serve the REST scaffold unless it is switched on (#7716)
* security(api): refuse to serve the REST scaffold unless it is switched on

No route in it consults a realm, a session or a token, and only the missing
vendor tree was keeping the endpoints quiet.

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

* fix(api): refuse with an empty 404 and use tabs in the test

A JSON error body confirmed an API was behind the refusal, which is what the
404 was chosen to avoid.

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

* test: resolve includes through Cacti path constants

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

* test: assert the include form the bootstrap can actually use

CACTI_PATH_INCLUDE is defined by global.php, so it does not exist at the
point that includes it. The file anchors on __DIR__ like its neighbours.

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

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
2026-08-21 12:30:21 -07:00
2b4140e646 fix: use get_client_addr() in API instead of raw REMOTE_ADDR (#6716)
* cleanup: remove unreachable defensive error logs in aggregate graph item validation

* fix: use get_client_addr() instead of raw REMOTE_ADDR in API

$_SERVER['REMOTE_ADDR'] bypasses proxy header validation,
IP filtering, and logging that get_client_addr() provides.
This matters when Cacti sits behind a reverse proxy.

Add Pest tests for get_client_addr() covering proxy header
handling, IPv6, invalid IPs, and config-driven header filtering.

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:52:05 -05:00
Thomas Vincent 710a533f5a docs: fix typos and grammar in api, locales, and service READMEs (#6690)
* docs: fix typos and grammar in api, locales, and service READMEs

api/README.md: fix PHP version requirement (7.4→8.1), replace
incorrect WSGI reference, fix formatting and punctuation.

locales/README.md: fix grammar (The the→While the), correct
spelling (on boarded→onboarded), fix typos (of if→or, if).

service/README.md: fix grammar (entering→entered, it's→its),
correct Debian user/group (www-run:www→www-data:www-data),
fix wording (for as a future→as a future, over write→overwrite).

No content changes; copy-editing only.

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

* docs: add router script to PHP built-in server command

PHP's built-in server doesn't route non-file paths to index.php
by default, so Slim endpoints return 404. Adding public/index.php
as the router script argument fixes this.

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

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
2026-03-02 08:57:28 -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 5d0a8850da QA: Fixing additional files at phpstan level 1 2025-11-18 22:19:32 -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
6de44a0fe7 Cacti Restuful API V0.1 (#6310)
* inital commit

* remove composer files

* Update api/public/index.php

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

* Update api/include/db_functions.php

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

* Add API Versioning

- Group Endpoint types together
- Add initial V1 endpoint groups
- Leverage the slim  route collector class

* Migrate db functions to Cacti core  db functions

* remove dedicated config file

* Update README.md

* Update db_functions.php

- include global and not the lib/database
- remove redudant db_connect function

* Sanity checks

- Ensure arrays are initialized before iterating

* Update db_functions.php

* Add logging

* helper function for parameter validation

* Update api/include/db_functions.php

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

* Sanitize error message

* Update db_functions.php

use the proper cacti db function
Leverage the read_config_option function instead of standalone db query

* Update api/include/db_functions.php

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

* Cleaning up  from pre migration to core cacti functions

* clean up

* update tholds endpoint

Call on the validate parameters helper function

* call on db_fetch_cell for thold db_function

* Update api/public/index.php

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

* Creat automation networks api endpoint

Call the proper db prepared function for prepared statments

* automation status endpoint

* data source stats status endpoint

* add validations (more to come)

* validations

* Update api/include/arrays.php

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

* Update api/include/db_functions.php

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

* Update api/include/arrays.php

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

* Update api/include/db_functions.php

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

* Refactor validation error handling in API routes

This changes adds a small bit of PSR formatting to the code, and reduces the length of the $validation_error by renaming to $verror for redability.

* Clean up whitespace in arrays.php

* Refactor SQL queries for improved readability

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: TheWitness <thewitness@cacti.net>
2025-09-11 13:06:45 -04:00
TheWitness 6d7e81e1d4 Feature: Adding slim and beginnings of an API 2025-08-20 21:14:39 -04:00