From 156c51224d42126469cbade0391d3eaa9611600f Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 28 Aug 2026 16:38:42 -0400 Subject: [PATCH] Fix client portal review findings: PIN wipe, log indexing, statement currency (db 2.7.8) Setting a PIN containing < or > silently cleared it: the length check ran before escapeSql(), whose strip_tags() then emptied the value, and the UPDATE stored the blank while flashing success. Length is now checked after sanitising. Password and PIN changes require the current password. SSO contacts are exempt - no local password to check, and the IdP already did it. New index on logs(log_user_id, log_client_id) for the portal profile and activity pages, which were scanning the whole table twice per profile view. admin/audit_logs.php's date filter rewritten as a half-open range so KEY log_created_at is usable - DATE(log_created_at) BETWEEN made it non-sargable. Portal statement page and PDF now render in the client's currency, matching the guest view and the emailed statement. Quick Send asks for confirmation; confirm-link extended to submit buttons. Portal audit entries logged an empty name - client/post.php used , which only exists agent-side. --- admin/audit_logs.php | 10 +++++- admin/database_updates/2.7.8.php | 38 +++++++++++++++++++++ agent/invoice.php | 10 ++++-- agent/invoices.php | 5 ++- agent/quote.php | 10 ++++-- agent/quotes.php | 5 ++- client/functions.php | 30 +++++++++++++++++ client/post.php | 58 +++++++++++++++++++++----------- client/profile.php | 20 +++++++++++ client/statement.php | 20 ++++++++--- db.sql | 3 +- js/confirm_modal.js | 40 +++++++++++++++++++--- 12 files changed, 213 insertions(+), 36 deletions(-) create mode 100644 admin/database_updates/2.7.8.php diff --git a/admin/audit_logs.php b/admin/audit_logs.php index ae0b3c44d..d69f5ac54 100644 --- a/admin/audit_logs.php +++ b/admin/audit_logs.php @@ -46,6 +46,14 @@ if (isset($_GET['action']) & !empty($_GET['action'])) { $action_filter = ''; } +/* + * The date filter is a half-open range rather than DATE(log_created_at) BETWEEN + * ... - wrapping the column in a function makes the comparison non-sargable, so + * KEY log_created_at could never be used and every page view scanned the whole + * table. '< dtt + 1 day' keeps the end date inclusive, which BETWEEN on a bare + * DATETIME would not: '2026-08-28' alone means midnight, and would drop that + * day's rows. + */ $sql = mysqli_query( $mysqli, "SELECT SQL_CALC_FOUND_ROWS client_id, client_name, log_action, log_created_at, log_description, log_entity_id, log_id, @@ -53,7 +61,7 @@ $sql = mysqli_query( LEFT JOIN users ON log_user_id = user_id LEFT JOIN clients ON log_client_id = client_id WHERE (log_type LIKE '%$q%' OR log_action LIKE '%$q%' OR log_description LIKE '%$q%' OR log_ip LIKE '%$q%' OR log_user_agent LIKE '%$q%' OR user_name LIKE '%$q%' OR client_name LIKE '%$q%') - AND DATE(log_created_at) BETWEEN '$dtf' AND '$dtt' + AND log_created_at >= '$dtf 00:00:00' AND log_created_at < DATE_ADD('$dtt', INTERVAL 1 DAY) $user_query $client_query $log_type_query diff --git a/admin/database_updates/2.7.8.php b/admin/database_updates/2.7.8.php new file mode 100644 index 000000000..7f7518748 --- /dev/null +++ b/admin/database_updates/2.7.8.php @@ -0,0 +1,38 @@ +