From 49a3c2d266f95bc8a695055a30b6381fcd187bb1 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Thu, 6 Aug 2026 11:00:49 -0400 Subject: [PATCH 01/25] Enforce client scoping on API expense reads and record updates Fixes (expenses/read.php missing apiClientScopeSql), plus an unscoped UPDATE in contacts/update.php and follow-up writes firing on zero-row updates in assets/credentials. --- api/v1/assets/update.php | 2 +- api/v1/contacts/update.php | 2 +- api/v1/credentials/update.php | 2 +- api/v1/expenses/read.php | 6 ++---- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/api/v1/assets/update.php b/api/v1/assets/update.php index db90b3e52..58e15684b 100644 --- a/api/v1/assets/update.php +++ b/api/v1/assets/update.php @@ -21,7 +21,7 @@ if (!empty($asset_id)) { $update_sql = mysqli_query($mysqli, "UPDATE assets SET asset_name = '$name', asset_description = '$description', asset_type = '$type', asset_make = '$make', asset_model = '$model', asset_serial = '$serial', asset_os = '$os', asset_uri = '$uri', asset_uri_2 = '$uri_2', asset_status = '$status', asset_location_id = $location, asset_vendor_id = $vendor, asset_contact_id = $contact, asset_purchase_date = $purchase_date, asset_warranty_expire = $warranty_expire, asset_install_date = $install_date, asset_notes = '$notes' WHERE asset_id = $asset_id AND asset_client_id = $client_id LIMIT 1"); // Check insert & get insert ID - if ($update_sql) { + if ($update_sql && $asset_row) { $update_count = mysqli_affected_rows($mysqli); // Update Primary Interface diff --git a/api/v1/contacts/update.php b/api/v1/contacts/update.php index c21ba9c5e..3dd27a693 100644 --- a/api/v1/contacts/update.php +++ b/api/v1/contacts/update.php @@ -23,7 +23,7 @@ if (!empty($contact_id)) { mysqli_query($mysqli,"UPDATE contacts SET contact_primary = 0 WHERE contact_client_id = $client_id"); } - $update_sql = mysqli_query($mysqli, "UPDATE contacts SET contact_name = '$name', contact_title = '$title', contact_department = '$department', contact_email = '$email', contact_phone = '$phone', contact_extension = '$extension', contact_mobile = '$mobile', contact_notes = '$notes', contact_primary = '$primary', contact_important = '$important', contact_billing = '$billing', contact_technical = '$technical', contact_location_id = $location_id, contact_client_id = $client_id WHERE contact_id = $contact_id LIMIT 1"); + $update_sql = mysqli_query($mysqli, "UPDATE contacts SET contact_name = '$name', contact_title = '$title', contact_department = '$department', contact_email = '$email', contact_phone = '$phone', contact_extension = '$extension', contact_mobile = '$mobile', contact_notes = '$notes', contact_primary = '$primary', contact_important = '$important', contact_billing = '$billing', contact_technical = '$technical', contact_location_id = $location_id, contact_client_id = $client_id WHERE contact_id = $contact_id AND contact_client_id = $client_id LIMIT 1"); // Check insert & get insert ID if ($update_sql) { diff --git a/api/v1/credentials/update.php b/api/v1/credentials/update.php index 049a02f07..a800253cb 100644 --- a/api/v1/credentials/update.php +++ b/api/v1/credentials/update.php @@ -20,7 +20,7 @@ if (!empty($_POST['api_key_decrypt_password']) && !empty($credential_id)) { $update_sql = mysqli_query($mysqli,"UPDATE credentials SET credential_name = '$name', credential_description = '$description', credential_uri = '$uri', credential_uri_2 = '$uri_2', credential_username = '$username', credential_password = '$password', credential_otp_secret = '$otp_secret', credential_note = '$note', credential_favorite = $favorite, credential_contact_id = $contact_id, credential_asset_id = $asset_id, credential_client_id = $client_id WHERE credential_id = '$credential_id' AND credential_client_id = $client_id LIMIT 1"); // Check insert & get insert ID - if ($update_sql) { + if ($update_sql && $credential_row) { $update_count = mysqli_affected_rows($mysqli); if ($password_changed) { diff --git a/api/v1/expenses/read.php b/api/v1/expenses/read.php index ddcd47c77..3bbb05779 100644 --- a/api/v1/expenses/read.php +++ b/api/v1/expenses/read.php @@ -5,18 +5,16 @@ require_once '../validate_api_key.php'; require_once '../require_get_method.php'; -// Expenses aren't client-scoped; access is gated by module_financial in enforce_api_rbac.php - if (isset($_GET['expense_id'])) { // Expense via ID (single) $id = intval($_GET['expense_id']); - $sql = mysqli_query($mysqli, "SELECT * FROM expenses WHERE expense_id = '$id'"); + $sql = mysqli_query($mysqli, "SELECT * FROM expenses WHERE expense_id = '$id' AND 1=1 " . apiClientScopeSql('expense_client_id') . ""); } else { // All expenses - $sql = mysqli_query($mysqli, "SELECT * FROM expenses ORDER BY expense_id LIMIT $limit OFFSET $offset"); + $sql = mysqli_query($mysqli, "SELECT * FROM expenses WHERE 1=1 " . apiClientScopeSql('expense_client_id') . " ORDER BY expense_id LIMIT $limit OFFSET $offset"); } // Output From 83383599a1226c715d1127085e235945a5ec32d4 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Thu, 6 Aug 2026 11:25:11 -0400 Subject: [PATCH 02/25] Add clientScopeSql helper for client-scoped list queries --- agent/reports/credential_rotation.php | 1 + api/v1/enforce_api_rbac.php | 20 +++------------- functions/auth.php | 33 +++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/agent/reports/credential_rotation.php b/agent/reports/credential_rotation.php index 2579f0421..253c8afa1 100644 --- a/agent/reports/credential_rotation.php +++ b/agent/reports/credential_rotation.php @@ -16,6 +16,7 @@ $passwords_not_rotated_sql = mysqli_query($mysqli, FROM credentials LEFT JOIN clients ON credential_client_id = client_id WHERE DATE(credential_password_changed_at) < DATE_SUB(CURDATE(), INTERVAL $days DAY) + " . clientScopeSql('credential_client_id') . " ORDER BY client_name" ); diff --git a/api/v1/enforce_api_rbac.php b/api/v1/enforce_api_rbac.php index c36ac9e3c..ef2b5b01f 100644 --- a/api/v1/enforce_api_rbac.php +++ b/api/v1/enforce_api_rbac.php @@ -45,24 +45,10 @@ function apiUserCanAccessClient($client_id) { } // Client-scope SQL fragment for a read query, from the user's allow / deny lists. -// Admin and unrestricted users get no restriction. Column-aware, so it works on any -// resource. Returns " AND ..." or "" (used after a "WHERE 1=1" anchor). +// Thin wrapper over clientScopeSql() in functions/auth.php so the API and the UI share one +// implementation. Kept under the api* name because every endpoint already calls it. function apiClientScopeSql($column) { - global $session_is_admin, $client_access_array, $client_deny_array; - if ($session_is_admin) { - return ''; - } - if (empty($client_access_array) && empty($client_deny_array)) { - return ''; // unrestricted user - all clients - } - $sql = ''; - if (!empty($client_access_array)) { - $sql .= " AND $column IN (" . implode(',', array_map('intval', $client_access_array)) . ")"; - } - if (!empty($client_deny_array)) { - $sql .= " AND $column NOT IN (" . implode(',', array_map('intval', $client_deny_array)) . ")"; - } - return $sql; + return clientScopeSql($column); } // --- Every key must be tied to a user (legacy keys were removed in the 2.4.7 migration) --- diff --git a/functions/auth.php b/functions/auth.php index f25cbb549..570091e2a 100644 --- a/functions/auth.php +++ b/functions/auth.php @@ -62,6 +62,39 @@ function enforceUserPermission($module, $check_access_level = 1) { } } +// Client-scope SQL fragment for a list query, built from the signed-in user's allow / deny lists. +// Admin and unrestricted users get no restriction. This is the list-level counterpart to +// enforceClientAccess(), which gates a single record. +// +// Column-aware on purpose: it scopes on the resource's OWN client column rather than a joined +// clients.client_id, so a row with no client (column = 0) is judged on its real value instead of +// becoming NULL through a LEFT JOIN and silently dropping out of the result set. +// +// Returns " AND ..." or "" - append it after a WHERE clause (add "WHERE 1=1" if there isn't one). +function clientScopeSql($column) { + global $session_is_admin, $client_access_array, $client_deny_array; + + if ($session_is_admin) { + return ''; + } + + if (empty($client_access_array) && empty($client_deny_array)) { + return ''; // Unrestricted user - all clients + } + + $sql = ''; + + if (!empty($client_access_array)) { + $sql .= " AND $column IN (" . implode(',', array_map('intval', $client_access_array)) . ")"; + } + + if (!empty($client_deny_array)) { + $sql .= " AND $column NOT IN (" . implode(',', array_map('intval', $client_deny_array)) . ")"; + } + + return $sql; +} + function enforceClientAccess($client_id = null) { global $mysqli, $session_user_id, $session_is_admin, $session_name; From ddd9c2b56ac607165c8129ccfc4b505b07007665 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Thu, 6 Aug 2026 11:45:56 -0400 Subject: [PATCH 03/25] clientScopeSql sweep whicn now removed the extra unessesary client joins --- agent/ajax.php | 12 ++++----- agent/assets.php | 6 ++--- agent/calendar.php | 12 ++++----- agent/certificates.php | 4 +-- agent/clients.php | 2 +- agent/contacts.php | 4 +-- agent/credentials.php | 4 +-- agent/domains.php | 4 +-- agent/expenses.php | 2 +- agent/global_search.php | 26 +++++++++---------- agent/includes/client_overview_side_nav.php | 18 ++++++------- agent/includes/get_side_nav_counts.php | 14 +++++----- agent/income.php | 5 ++-- agent/invoice.php | 2 +- agent/invoices.php | 4 +-- agent/locations.php | 4 +-- agent/modals/asset/asset_add.php | 2 +- agent/modals/certificate/certificate_add.php | 2 +- agent/modals/contact/contact_add.php | 2 +- agent/modals/credential/credential_add.php | 2 +- agent/modals/domain/domain_add.php | 2 +- agent/modals/expense/expense_add.php | 2 +- .../expense/expense_bulk_edit_client.php | 2 +- agent/modals/expense/expense_copy.php | 2 +- agent/modals/expense/expense_edit.php | 2 +- agent/modals/invoice/invoice_add.php | 2 +- agent/modals/location/location_add.php | 2 +- agent/modals/network/network_add.php | 2 +- agent/modals/project/project_add.php | 2 +- agent/modals/quote/quote_add.php | 2 +- .../recurring_expense_add.php | 2 +- .../recurring_expense_edit.php | 2 +- .../recurring_invoice_add.php | 2 +- .../recurring_ticket/recurring_ticket_add.php | 2 +- agent/modals/service/service_add.php | 2 +- agent/modals/software/software_add.php | 2 +- .../software/software_add_from_template.php | 2 +- agent/modals/ticket/ticket_add.php | 2 +- agent/modals/ticket/ticket_change_client.php | 2 +- agent/modals/ticket/ticket_edit.php | 10 ++----- agent/modals/ticket/ticket_invoice_add.php | 2 +- agent/modals/ticket/ticket_merge.php | 2 +- agent/modals/ticket/ticket_quote_add.php | 2 +- agent/modals/trip/trip_add.php | 2 +- agent/modals/trip/trip_copy.php | 2 +- agent/modals/trip/trip_edit.php | 2 +- agent/networks.php | 4 +-- agent/post/asset.php | 2 +- agent/post/certificate.php | 2 +- agent/post/client.php | 2 +- agent/post/contact.php | 2 +- agent/post/credential.php | 2 +- agent/post/domain.php | 2 +- agent/post/expense.php | 2 +- agent/post/income.php | 2 +- agent/post/invoice.php | 6 ++--- agent/post/location.php | 2 +- agent/post/network.php | 2 +- agent/post/quote.php | 4 +-- agent/post/recurring_invoice.php | 2 +- agent/post/software.php | 2 +- agent/post/ticket.php | 8 ++---- agent/post/trip.php | 2 +- agent/post/vendor.php | 2 +- agent/project.php | 9 +------ agent/projects.php | 9 +------ agent/quote.php | 2 +- agent/quotes.php | 2 +- agent/recurring_expenses.php | 2 +- agent/recurring_invoices.php | 2 +- agent/recurring_tickets.php | 2 +- agent/services.php | 4 +-- agent/software.php | 4 +-- agent/ticket.php | 7 ++--- agent/tickets.php | 7 ++--- agent/trips.php | 2 +- agent/vendors.php | 2 +- functions/auth.php | 5 +++- includes/load_user_session.php | 13 ++-------- 79 files changed, 139 insertions(+), 174 deletions(-) diff --git a/agent/ajax.php b/agent/ajax.php index 40d7ca1d9..afbe60d45 100644 --- a/agent/ajax.php +++ b/agent/ajax.php @@ -294,7 +294,7 @@ if (isset($_GET['get_active_clients'])) { $mysqli, "SELECT client_id, client_name FROM clients WHERE client_archived_at IS NULL - $access_permission_query + " . clientScopeSql('clients.client_id') . " ORDER BY client_accessed_at DESC" ); @@ -320,7 +320,7 @@ if (isset($_GET['get_client_contacts'])) { "SELECT contact_id, contact_name, contact_title, contact_email, contact_primary, contact_important, contact_technical FROM contacts LEFT JOIN clients on contact_client_id = client_id WHERE contacts.contact_archived_at IS NULL AND contact_client_id = $client_id - $access_permission_query + " . clientScopeSql('contact_client_id') . " ORDER BY contact_primary DESC, contact_technical DESC, contact_important DESC, contact_name" ); @@ -350,7 +350,7 @@ if (isset($_GET['get_client_assets'])) { LEFT JOIN clients on asset_client_id = client_id LEFT JOIN contacts ON contact_id = asset_contact_id WHERE assets.asset_archived_at IS NULL AND asset_client_id = $client_id - $access_permission_query + " . clientScopeSql('asset_client_id') . " ORDER BY asset_type ASC, asset_favorite DESC, asset_name" ); @@ -379,7 +379,7 @@ if (isset($_GET['get_client_locations'])) { "SELECT location_id, location_name FROM locations LEFT JOIN clients on location_client_id = client_id WHERE locations.location_archived_at IS NULL AND location_client_id = $client_id - $access_permission_query + " . clientScopeSql('location_client_id') . " ORDER BY location_primary DESC, location_name ASC" ); @@ -408,7 +408,7 @@ if (isset($_GET['get_client_vendors'])) { "SELECT vendor_id, vendor_name FROM vendors LEFT JOIN clients on vendor_client_id = client_id WHERE vendors.vendor_archived_at IS NULL AND vendor_client_id = $client_id - $access_permission_query + " . clientScopeSql('vendor_client_id') . " ORDER BY vendor_name ASC" ); @@ -437,7 +437,7 @@ if (isset($_GET['get_client_projects'])) { "SELECT project_id, project_name FROM projects LEFT JOIN clients on project_client_id = client_id WHERE projects.project_archived_at IS NULL AND projects.project_completed_at IS NULL AND project_client_id = $client_id - $access_permission_query + " . clientScopeSql('project_client_id') . " ORDER BY project_name ASC" ); diff --git a/agent/assets.php b/agent/assets.php index 32eb370ce..bb0d8ded4 100644 --- a/agent/assets.php +++ b/agent/assets.php @@ -124,7 +124,7 @@ $row = mysqli_fetch_assoc(mysqli_query($mysqli, " LEFT JOIN tags ON tag_id = asset_tag_tag_id WHERE $archive_query $tag_query - $access_permission_query + " . clientScopeSql('asset_client_id') . " $client_query GROUP BY asset_id ) AS filtered_assets; @@ -161,7 +161,7 @@ $sql = mysqli_query( $tag_query AND (asset_name LIKE '%$q%' OR asset_description LIKE '%$q%' OR asset_type LIKE '%$q%' OR interface_ip LIKE '%$q%' OR interface_ipv6 LIKE '%$q%' OR interface_mac LIKE '%$q%' OR asset_make LIKE '%$q%' OR asset_model LIKE '%$q%' OR asset_serial LIKE '%$q%' OR asset_os LIKE '%$q%' OR contact_name LIKE '%$q%' OR location_name LIKE '%$q%' OR client_name LIKE '%$q%' OR tag_name LIKE '%$q%') AND ($type_query) - $access_permission_query + " . clientScopeSql('asset_client_id') . " $location_query $expire_query $client_query @@ -288,7 +288,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); FROM clients JOIN assets ON asset_client_id = client_id WHERE $archive_query - $access_permission_query + " . clientScopeSql('clients.client_id') . " ORDER BY client_name ASC "); while ($row = mysqli_fetch_assoc($sql_clients_filter)) { diff --git a/agent/calendar.php b/agent/calendar.php index ead5c3b93..ceb20d164 100644 --- a/agent/calendar.php +++ b/agent/calendar.php @@ -341,7 +341,7 @@ while ($row = mysqli_fetch_assoc($sql)) { } // Invoices Created - $sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN invoices ON client_id = invoice_client_id $client_query $access_permission_query"); + $sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN invoices ON client_id = invoice_client_id $client_query " . clientScopeSql('clients.client_id') . ""); while ($row = mysqli_fetch_assoc($sql)) { $event_id = intval($row['invoice_id']); $scope = strval($row['invoice_scope']); @@ -356,7 +356,7 @@ while ($row = mysqli_fetch_assoc($sql)) { } // Quotes Created - $sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN quotes ON client_id = quote_client_id $client_query $access_permission_query"); + $sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN quotes ON client_id = quote_client_id $client_query " . clientScopeSql('clients.client_id') . ""); while ($row = mysqli_fetch_assoc($sql)) { $event_id = intval($row['quote_id']); $event_title = json_encode($row['quote_prefix'] . $row['quote_number'] . " " . $row['quote_scope']); @@ -370,7 +370,7 @@ while ($row = mysqli_fetch_assoc($sql)) { LEFT JOIN tickets ON client_id = ticket_client_id LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id LEFT JOIN users ON ticket_assigned_to = user_id - $client_query $access_permission_query" + $client_query " . clientScopeSql('clients.client_id') . "" ); while ($row = mysqli_fetch_assoc($sql)) { $event_id = intval($row['ticket_id']); @@ -404,7 +404,7 @@ while ($row = mysqli_fetch_assoc($sql)) { $sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN recurring_tickets ON client_id = recurring_ticket_client_id LEFT JOIN users ON recurring_ticket_assigned_to = user_id - $client_query $access_permission_query" + $client_query " . clientScopeSql('clients.client_id') . "" ); while ($row = mysqli_fetch_assoc($sql)) { $event_id = intval($row['recurring_ticket_id']); @@ -429,7 +429,7 @@ while ($row = mysqli_fetch_assoc($sql)) { LEFT JOIN tickets ON client_id = ticket_client_id LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id LEFT JOIN users ON ticket_assigned_to = user_id - $client_query $access_permission_query AND ticket_schedule IS NOT NULL" + $client_query " . clientScopeSql('clients.client_id') . " AND ticket_schedule IS NOT NULL" ); while ($row = mysqli_fetch_assoc($sql)) { $event_id = intval($row['ticket_id']); @@ -460,7 +460,7 @@ while ($row = mysqli_fetch_assoc($sql)) { } // Vendors Added Created - $sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN vendors ON client_id = vendor_client_id $client_query $access_permission_query"); + $sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN vendors ON client_id = vendor_client_id $client_query " . clientScopeSql('clients.client_id') . ""); while ($row = mysqli_fetch_assoc($sql)) { $event_id = intval($row['vendor_id']); $client_id = intval($row['client_id']); diff --git a/agent/certificates.php b/agent/certificates.php index 5b1219868..ce8dec84f 100644 --- a/agent/certificates.php +++ b/agent/certificates.php @@ -65,7 +65,7 @@ $sql = mysqli_query($mysqli, "SELECT SQL_CALC_FOUND_ROWS * FROM certificates LEFT JOIN clients ON client_id = certificate_client_id WHERE $archive_query AND (certificate_name LIKE '%$q%' OR certificate_domain LIKE '%$q%' OR certificate_description LIKE '%$q%' OR certificate_issued_by LIKE '%$q%' OR client_name LIKE '%$q%') - $access_permission_query + " . clientScopeSql('certificate_client_id') . " $client_query $expire_query ORDER BY $sort $order LIMIT $record_from, $record_to" @@ -122,7 +122,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); FROM clients JOIN certificates ON certificate_client_id = client_id WHERE $archive_query - $access_permission_query + " . clientScopeSql('clients.client_id') . " ORDER BY client_name ASC "); while ($row = mysqli_fetch_assoc($sql_clients_filter)) { diff --git a/agent/clients.php b/agent/clients.php index 9c621dd79..cd831c582 100644 --- a/agent/clients.php +++ b/agent/clients.php @@ -67,7 +67,7 @@ $sql = mysqli_query( AND client_$archive_query AND DATE(client_created_at) BETWEEN '$dtf' AND '$dtt' $leads_query - $access_permission_query + " . clientScopeSql('clients.client_id') . " $tag_query $industry_query $referral_query diff --git a/agent/contacts.php b/agent/contacts.php index e716fcf84..933d02e42 100644 --- a/agent/contacts.php +++ b/agent/contacts.php @@ -74,7 +74,7 @@ $sql = mysqli_query($mysqli, "SELECT SQL_CALC_FOUND_ROWS contacts.*, clients.*, WHERE $archive_query $tag_query AND (contact_name LIKE '%$q%' OR contact_title LIKE '%$q%' OR location_name LIKE '%$q%' OR contact_email LIKE '%$q%' OR contact_department LIKE '%$q%' OR contact_phone LIKE '%$phone_query%' OR contact_extension LIKE '%$q%' OR contact_mobile LIKE '%$phone_query%' OR tag_name LIKE '%$q%' OR client_name LIKE '%$q%') - $access_permission_query + " . clientScopeSql('contact_client_id') . " $client_query $location_query GROUP BY contact_id @@ -193,7 +193,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); FROM clients JOIN contacts ON contact_client_id = client_id WHERE $archive_query - $access_permission_query + " . clientScopeSql('clients.client_id') . " ORDER BY client_name ASC "); while ($row = mysqli_fetch_assoc($sql_clients_filter)) { diff --git a/agent/credentials.php b/agent/credentials.php index cd59b4a67..3b9797fa9 100644 --- a/agent/credentials.php +++ b/agent/credentials.php @@ -90,7 +90,7 @@ $sql = mysqli_query( $tag_query AND (c.credential_name LIKE '%$q%' OR c.credential_description LIKE '%$q%' OR c.credential_uri LIKE '%$q%' OR tag_name LIKE '%$q%' OR client_name LIKE '%$q%') $location_query - $access_permission_query + " . clientScopeSql('credential_client_id') . " $client_query GROUP BY c.credential_id ORDER BY c.credential_favorite DESC, $sort $order LIMIT $record_from, $record_to" @@ -204,7 +204,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); FROM clients JOIN credentials ON credential_client_id = client_id WHERE $archive_query - $access_permission_query + " . clientScopeSql('clients.client_id') . " ORDER BY client_name ASC "); while ($row = mysqli_fetch_assoc($sql_clients_filter)) { diff --git a/agent/domains.php b/agent/domains.php index 3ab3d3bce..a04b4df13 100644 --- a/agent/domains.php +++ b/agent/domains.php @@ -78,7 +78,7 @@ $sql = mysqli_query($mysqli, "SELECT SQL_CALC_FOUND_ROWS domains.*, clients.*, LEFT JOIN vendors AS webhost ON domains.domain_webhost = webhost.vendor_id WHERE (domains.domain_name LIKE '%$q%' OR domains.domain_description LIKE '%$q%' OR registrar.vendor_name LIKE '%$q%' OR dnshost.vendor_name LIKE '%$q%' OR mailhost.vendor_name LIKE '%$q%' OR webhost.vendor_name LIKE '%$q%' OR client_name LIKE '%$q%') AND $archive_query - $access_permission_query + " . clientScopeSql('domain_client_id') . " $client_query $expire_query ORDER BY $sort $order LIMIT $record_from, $record_to"); @@ -134,7 +134,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); FROM clients JOIN domains ON domain_client_id = client_id WHERE $archive_query - $access_permission_query + " . clientScopeSql('clients.client_id') . " ORDER BY client_name ASC "); while ($row = mysqli_fetch_assoc($sql_clients_filter)) { diff --git a/agent/expenses.php b/agent/expenses.php index beb8bbac6..1e82aacf2 100644 --- a/agent/expenses.php +++ b/agent/expenses.php @@ -52,7 +52,7 @@ $sql = mysqli_query( $category_query AND (vendor_name LIKE '%$q%' OR client_name LIKE '%$q%' OR category_name LIKE '%$q%' OR account_name LIKE '%$q%' OR expense_description LIKE '%$q%' OR expense_amount LIKE '%$q%') $account_query - $access_permission_query + " . clientScopeSql('expense_client_id') . " ORDER BY $sort $order LIMIT $record_from, $record_to" ); diff --git a/agent/global_search.php b/agent/global_search.php index a82c776a6..3d5017346 100644 --- a/agent/global_search.php +++ b/agent/global_search.php @@ -32,7 +32,7 @@ if (isset($_GET['query'])) { LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1 WHERE client_archived_at IS NULL AND (client_name LIKE '%$query%' OR client_abbreviation LIKE '%$query%') - $access_permission_query + " . clientScopeSql('clients.client_id') . " ORDER BY client_id DESC LIMIT 5" ); @@ -44,7 +44,7 @@ if (isset($_GET['query'])) { OR contact_email LIKE '%$query%' OR contact_phone LIKE '%$phone_query%' OR contact_mobile LIKE '%$phone_query%') - $access_permission_query + " . clientScopeSql('contact_client_id') . " ORDER BY contact_id DESC LIMIT 5" ); @@ -52,7 +52,7 @@ if (isset($_GET['query'])) { LEFT JOIN clients ON vendor_client_id = client_id WHERE vendor_archived_at IS NULL AND (vendor_name LIKE '%$query%' OR vendor_phone LIKE '%$phone_query%') - $access_permission_query + " . clientScopeSql('vendor_client_id') . " ORDER BY vendor_id DESC LIMIT 5" ); @@ -60,7 +60,7 @@ if (isset($_GET['query'])) { LEFT JOIN clients ON domain_client_id = client_id WHERE domain_archived_at IS NULL AND domain_name LIKE '%$query%' - $access_permission_query + " . clientScopeSql('domain_client_id') . " ORDER BY domain_id DESC LIMIT 5" ); @@ -74,7 +74,7 @@ if (isset($_GET['query'])) { LEFT JOIN clients on document_client_id = clients.client_id WHERE document_archived_at IS NULL AND MATCH(document_content_raw) AGAINST ('$query') - $access_permission_query + " . clientScopeSql('document_client_id') . " ORDER BY document_id DESC LIMIT 5" ); @@ -84,7 +84,7 @@ if (isset($_GET['query'])) { WHERE file_archived_at IS NULL AND (file_name LIKE '%$query%' OR file_description LIKE '%$query%') - $access_permission_query + " . clientScopeSql('file_client_id') . " ORDER BY file_id DESC LIMIT 5" ); @@ -96,7 +96,7 @@ if (isset($_GET['query'])) { OR ticket_details LIKE '%$query%' OR CONCAT(ticket_prefix,ticket_number) LIKE '%$query%' OR ticket_number = '$ticket_num_query') - $access_permission_query + " . clientScopeSql('tickets.ticket_client_id') . " ORDER BY ticket_id DESC LIMIT 5" ); @@ -104,7 +104,7 @@ if (isset($_GET['query'])) { LEFT JOIN clients ON recurring_ticket_client_id = client_id WHERE (recurring_ticket_subject LIKE '%$query%' OR recurring_ticket_details LIKE '%$query%') - $access_permission_query + " . clientScopeSql('recurring_ticket_client_id') . " ORDER BY recurring_ticket_id DESC LIMIT 5" ); @@ -113,7 +113,7 @@ if (isset($_GET['query'])) { LEFT JOIN clients ON credential_client_id = client_id WHERE credential_archived_at IS NULL AND (credential_name LIKE '%$query%' OR credential_description LIKE '%$query%') - $access_permission_query + " . clientScopeSql('credential_client_id') . " ORDER BY credential_id DESC LIMIT 5" ); @@ -122,7 +122,7 @@ if (isset($_GET['query'])) { LEFT JOIN categories ON quote_category_id = category_id WHERE quote_archived_at IS NULL AND (CONCAT(quote_prefix,quote_number) LIKE '%$query%' OR quote_number LIKE '%$query%' OR quote_scope LIKE '%$query%') - $access_permission_query + " . clientScopeSql('quote_client_id') . " ORDER BY quote_number DESC LIMIT 5" ); @@ -131,7 +131,7 @@ if (isset($_GET['query'])) { LEFT JOIN categories ON invoice_category_id = category_id WHERE invoice_archived_at IS NULL AND (CONCAT(invoice_prefix,invoice_number) LIKE '%$query%' OR invoice_number LIKE '%$query%' OR invoice_scope LIKE '%$query%') - $access_permission_query + " . clientScopeSql('invoice_client_id') . " ORDER BY invoice_number DESC LIMIT 5" ); @@ -142,7 +142,7 @@ if (isset($_GET['query'])) { LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1 WHERE asset_archived_at IS NULL AND (asset_name LIKE '%$query%' OR asset_description LIKE '%$query%' OR asset_type LIKE '%$query%' OR asset_make LIKE '%$query%' OR asset_model LIKE '%$query%' OR asset_serial LIKE '%$query%' OR asset_os LIKE '%$query%' OR interface_ip LIKE '%$query%' OR interface_nat_ip LIKE '%$query%' OR interface_mac LIKE '%$query%' OR asset_status LIKE '%$query%') - $access_permission_query + " . clientScopeSql('asset_client_id') . " ORDER BY asset_name DESC LIMIT 5" ); @@ -151,7 +151,7 @@ if (isset($_GET['query'])) { LEFT JOIN clients ON ticket_client_id = client_id WHERE ticket_reply_archived_at IS NULL AND (ticket_reply LIKE '%$query%') - $access_permission_query + " . clientScopeSql('ticket_client_id') . " ORDER BY ticket_id DESC, ticket_reply_id ASC LIMIT 20" ); diff --git a/agent/includes/client_overview_side_nav.php b/agent/includes/client_overview_side_nav.php index 53d63c197..6b3c912d8 100644 --- a/agent/includes/client_overview_side_nav.php +++ b/agent/includes/client_overview_side_nav.php @@ -1,31 +1,31 @@ diff --git a/agent/includes/get_side_nav_counts.php b/agent/includes/get_side_nav_counts.php index 87dac0873..14bab8da9 100644 --- a/agent/includes/get_side_nav_counts.php +++ b/agent/includes/get_side_nav_counts.php @@ -2,31 +2,31 @@ // Get Main Side Bar Badge Counts // Active Clients Count -$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('client_id') AS num FROM clients WHERE client_archived_at IS NULL $access_permission_query")); +$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('client_id') AS num FROM clients WHERE client_archived_at IS NULL " . clientScopeSql('clients.client_id') . "")); $num_active_clients = $row['num']; // Active Ticket Count -$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('ticket_id') AS num FROM tickets LEFT JOIN clients ON client_id = ticket_client_id WHERE ticket_archived_at IS NULL AND ticket_closed_at IS NULL AND ticket_status != 4 $access_permission_query")); +$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('ticket_id') AS num FROM tickets WHERE ticket_archived_at IS NULL AND ticket_closed_at IS NULL AND ticket_status != 4 " . clientScopeSql('ticket_client_id') . "")); $num_active_tickets = $row['num']; // Recurring Ticket Count -$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('recurring_ticket_id') AS num FROM recurring_tickets LEFT JOIN clients ON client_id = recurring_ticket_client_id WHERE 1 = 1 $access_permission_query")); +$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('recurring_ticket_id') AS num FROM recurring_tickets WHERE 1 = 1 " . clientScopeSql('recurring_ticket_client_id') . "")); $num_recurring_tickets = $row['num']; // Active Project Count -$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('project_id') AS num FROM projects LEFT JOIN clients ON project_client_id = client_id WHERE project_archived_at IS NULL AND project_completed_at IS NULL $access_permission_query")); +$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('project_id') AS num FROM projects WHERE project_archived_at IS NULL AND project_completed_at IS NULL " . clientScopeSql('project_client_id') . "")); $num_active_projects = $row['num']; // Open Invoices Count -$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('invoice_id') AS num FROM invoices LEFT JOIN clients ON invoice_client_id = client_id WHERE (invoice_status = 'Sent' OR invoice_status = 'Viewed' OR invoice_status = 'Partial' OR invoice_status = 'Draft') AND invoice_archived_at IS NULL $access_permission_query")); +$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('invoice_id') AS num FROM invoices WHERE (invoice_status = 'Sent' OR invoice_status = 'Viewed' OR invoice_status = 'Partial' OR invoice_status = 'Draft') AND invoice_archived_at IS NULL " . clientScopeSql('invoice_client_id') . "")); $num_open_invoices = $row['num']; // Recurring Invoice Count -$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('recurring_invoice_id') AS num FROM recurring_invoices LEFT JOIN clients ON recurring_invoice_client_id = client_id WHERE recurring_invoice_archived_at IS NULL $access_permission_query")); +$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('recurring_invoice_id') AS num FROM recurring_invoices WHERE recurring_invoice_archived_at IS NULL " . clientScopeSql('recurring_invoice_client_id') . "")); $num_recurring_invoices = $row['num']; // Open Quotes Count -$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('quote_id') AS num FROM quotes LEFT JOIN clients ON quote_client_id = client_id WHERE (quote_status = 'Sent' OR quote_status = 'Viewed') AND quote_archived_at IS NULL $access_permission_query")); +$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('quote_id') AS num FROM quotes WHERE (quote_status = 'Sent' OR quote_status = 'Viewed') AND quote_archived_at IS NULL " . clientScopeSql('quote_client_id') . "")); $num_open_quotes = $row['num']; // Recurring Expenses Count diff --git a/agent/income.php b/agent/income.php index e74f044fa..31a98a02c 100644 --- a/agent/income.php +++ b/agent/income.php @@ -91,7 +91,7 @@ $income_query = LEFT JOIN categories ON invoice_category_id = category_id WHERE payment_archived_at IS NULL $payment_client_query - $access_permission_query + " . clientScopeSql('invoice_client_id') . " UNION ALL @@ -120,7 +120,8 @@ $income_query = LEFT JOIN transfers ON transfer_revenue_id = revenue_id WHERE revenue_archived_at IS NULL AND transfer_id IS NULL - $revenue_client_query"; + $revenue_client_query + " . clientScopeSql('revenue_client_id') . ""; $income_filter_query = "WHERE DATE(income_date) BETWEEN '$dtf' AND '$dtt' diff --git a/agent/invoice.php b/agent/invoice.php index 296d1c816..5bd6cb90c 100644 --- a/agent/invoice.php +++ b/agent/invoice.php @@ -21,7 +21,7 @@ if (isset($_GET['invoice_id'])) { LEFT JOIN contacts ON client_id = contact_client_id AND contact_primary = 1 LEFT JOIN locations ON client_id = location_client_id AND location_primary = 1 WHERE invoice_id = $invoice_id - $access_permission_query + " . clientScopeSql('invoice_client_id') . " LIMIT 1" ); diff --git a/agent/invoices.php b/agent/invoices.php index 7e5c7a517..e56a96527 100644 --- a/agent/invoices.php +++ b/agent/invoices.php @@ -11,7 +11,7 @@ if (isset($_GET['client_id'])) { $client_url = "client_id=$client_id&"; } else { require_once "includes/inc_all.php"; - $client_query = "$access_permission_query"; + $client_query = clientScopeSql('invoice_client_id'); $client_url = ''; } @@ -103,7 +103,7 @@ $sql = mysqli_query( $category_query AND DATE(invoice_date) BETWEEN '$dtf' AND '$dtt' AND (CONCAT(invoice_prefix,invoice_number) LIKE '%$q%' OR invoice_scope LIKE '%$q%' OR client_name LIKE '%$q%' OR invoice_status LIKE '%$q%' OR invoice_amount LIKE '%$q%' OR category_name LIKE '%$q%') - $access_permission_query + " . clientScopeSql('invoice_client_id') . " $client_query ORDER BY $sort $order LIMIT $record_from, $record_to" ); diff --git a/agent/locations.php b/agent/locations.php index e041987a8..a5eb1ffe0 100644 --- a/agent/locations.php +++ b/agent/locations.php @@ -64,7 +64,7 @@ $sql = mysqli_query( WHERE $archive_query $tag_query AND (location_name LIKE '%$q%' OR location_description LIKE '%$q%' OR location_address LIKE '%$q%' OR location_city LIKE '%$q%' OR location_state LIKE '%$q%' OR location_zip LIKE '%$q%' OR location_country LIKE '%$q%' OR location_phone LIKE '%$phone_query%' OR tag_name LIKE '%$q%' OR client_name LIKE '%$q%') - $access_permission_query + " . clientScopeSql('location_client_id') . " $client_query GROUP BY location_id ORDER BY location_primary DESC, $sort $order LIMIT $record_from, $record_to" @@ -154,7 +154,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); FROM clients JOIN locations ON location_client_id = client_id WHERE $archive_query - $access_permission_query + " . clientScopeSql('clients.client_id') . " ORDER BY client_name ASC "); while ($row = mysqli_fetch_assoc($sql_clients_filter)) { diff --git a/agent/modals/asset/asset_add.php b/agent/modals/asset/asset_add.php index c6da21baf..21cf097c2 100644 --- a/agent/modals/asset/asset_add.php +++ b/agent/modals/asset/asset_add.php @@ -12,7 +12,7 @@ if ($client_id) { $sql_location_select = mysqli_query($mysqli, "SELECT location_id, location_name FROM locations WHERE location_archived_at IS NULL AND location_client_id = $client_id ORDER BY location_name ASC"); $sql_contact_select = mysqli_query($mysqli, "SELECT * FROM contacts WHERE contact_archived_at IS NULL AND contact_client_id = $client_id ORDER BY contact_name ASC"); } else { - $sql_client_select = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients WHERE client_archived_at IS NULL $access_permission_query ORDER BY client_name ASC"); + $sql_client_select = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients WHERE client_archived_at IS NULL " . clientScopeSql('clients.client_id') . " ORDER BY client_name ASC"); } // OS typeahead suggestions diff --git a/agent/modals/certificate/certificate_add.php b/agent/modals/certificate/certificate_add.php index 6fb80d1dd..29d2b33dc 100644 --- a/agent/modals/certificate/certificate_add.php +++ b/agent/modals/certificate/certificate_add.php @@ -50,7 +50,7 @@ ob_start(); diff --git a/agent/modals/contact/contact_add.php b/agent/modals/contact/contact_add.php index 5f7196562..294c071f3 100644 --- a/agent/modals/contact/contact_add.php +++ b/agent/modals/contact/contact_add.php @@ -7,7 +7,7 @@ $client_id = intval($_GET['client_id'] ?? 0); if ($client_id) { $sql_location_select = mysqli_query($mysqli, "SELECT location_id, location_name FROM locations WHERE location_archived_at IS NULL AND location_client_id = $client_id ORDER BY location_name ASC"); } else { - $sql_client_select = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients WHERE client_archived_at IS NULL $access_permission_query ORDER BY client_name ASC"); + $sql_client_select = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients WHERE client_archived_at IS NULL " . clientScopeSql('clients.client_id') . " ORDER BY client_name ASC"); } $sql_tags_select = mysqli_query($mysqli, "SELECT tag_id, tag_name FROM tags WHERE tag_type = 3 ORDER BY tag_name ASC"); diff --git a/agent/modals/credential/credential_add.php b/agent/modals/credential/credential_add.php index 7e0f4035e..4f5ebf339 100644 --- a/agent/modals/credential/credential_add.php +++ b/agent/modals/credential/credential_add.php @@ -54,7 +54,7 @@ ob_start(); diff --git a/agent/modals/domain/domain_add.php b/agent/modals/domain/domain_add.php index 50fae188b..1c57d62c6 100644 --- a/agent/modals/domain/domain_add.php +++ b/agent/modals/domain/domain_add.php @@ -48,7 +48,7 @@ ob_start(); diff --git a/agent/modals/expense/expense_add.php b/agent/modals/expense/expense_add.php index 32a865472..801150598 100644 --- a/agent/modals/expense/expense_add.php +++ b/agent/modals/expense/expense_add.php @@ -169,7 +169,7 @@ ob_start(); - No Client - - Select Client - - Select Client - - Select a Client - - Select Client - diff --git a/agent/modals/network/network_add.php b/agent/modals/network/network_add.php index 97eeafcf3..67abf4cef 100644 --- a/agent/modals/network/network_add.php +++ b/agent/modals/network/network_add.php @@ -54,7 +54,7 @@ ob_start(); diff --git a/agent/modals/project/project_add.php b/agent/modals/project/project_add.php index 09b0ef253..852efe405 100644 --- a/agent/modals/project/project_add.php +++ b/agent/modals/project/project_add.php @@ -30,7 +30,7 @@ ob_start(); - Client (Optional) - - Client (Optional) - - Client (Optional) - 'Search', 'value' => stripslashes(escapeHtml($q)), 'drop' => 'q'); } -// Ticket client access overide - This is the only way to show tickets without a client to agents with restricted client access -$access_permission_query_overide = ''; -if ($client_access_string) { - $access_permission_query_overide = "AND ticket_client_id IN (0,$client_access_string)"; -} +// Tickets with no client stay visible to restricted agents - clientScopeSql() includes 0 +$access_permission_query_overide = clientScopeSql('ticket_client_id'); /* * Columns the two views need. Explicit rather than SELECT * - the tickets diff --git a/agent/trips.php b/agent/trips.php index cd0458a3e..bc8abd7f6 100644 --- a/agent/trips.php +++ b/agent/trips.php @@ -24,7 +24,7 @@ $sql = mysqli_query( AND DATE(trip_date) BETWEEN '$dtf' AND '$dtt' AND trip_archived_at IS NULL $client_query - $access_permission_query + " . clientScopeSql('trip_client_id') . " ORDER BY $sort $order LIMIT $record_from, $record_to" ); diff --git a/agent/vendors.php b/agent/vendors.php index b8f2bd32b..000eedef4 100644 --- a/agent/vendors.php +++ b/agent/vendors.php @@ -23,7 +23,7 @@ $sql = mysqli_query( WHERE vendor_$archive_query AND (vendor_name LIKE '%$q%' OR vendor_description LIKE '%$q%' OR vendor_account_number LIKE '%$q%' OR vendor_website LIKE '%$q%' OR vendor_contact_name LIKE '%$q%' OR vendor_email LIKE '%$q%' OR vendor_phone LIKE '%$phone_query%') $client_query - $access_permission_query + " . clientScopeSql('vendor_client_id') . " ORDER BY $sort $order LIMIT $record_from, $record_to" ); diff --git a/functions/auth.php b/functions/auth.php index 570091e2a..d6acd13c7 100644 --- a/functions/auth.php +++ b/functions/auth.php @@ -84,8 +84,11 @@ function clientScopeSql($column) { $sql = ''; + // 0 is included deliberately: a record with no client isn't any client's data, so a + // restricted user keeps seeing it. This also matches the deny branch below, where 0 + // already passes NOT IN, and the old hand-rolled ticket override that did IN (0,...). if (!empty($client_access_array)) { - $sql .= " AND $column IN (" . implode(',', array_map('intval', $client_access_array)) . ")"; + $sql .= " AND $column IN (0," . implode(',', array_map('intval', $client_access_array)) . ")"; } if (!empty($client_deny_array)) { diff --git a/includes/load_user_session.php b/includes/load_user_session.php index 00c3997af..bfd61bb96 100644 --- a/includes/load_user_session.php +++ b/includes/load_user_session.php @@ -63,16 +63,7 @@ while ($row = mysqli_fetch_assoc($user_client_access_result)) { } } +// Client scoping for queries is built per-query by clientScopeSql() in functions/auth.php, +// which is column-aware. These strings remain for any caller that needs the raw lists. $client_access_string = implode(',', $client_access_array); $client_deny_string = implode(',', $client_deny_array); - -$access_permission_query = ""; -if (!$session_is_admin) { - // Restrict to the allow list (if any), then subtract the deny list - if ($client_access_string) { - $access_permission_query .= " AND clients.client_id IN ($client_access_string)"; - } - if ($client_deny_string) { - $access_permission_query .= " AND clients.client_id NOT IN ($client_deny_string)"; - } -} From eb2cc3d653111028d5e780cadea37dac70da4c78 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Thu, 6 Aug 2026 11:55:39 -0400 Subject: [PATCH 04/25] Update Contributing with the new clientScopeSql function --- CONTRIBUTING.md | 21 ++++++++++++++++++++- includes/load_user_session.php | 5 ----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3e076677d..ac74a5b51 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -171,7 +171,24 @@ Everywhere else — anything under `agent/post/` — the call belongs in the blo ### 4. Client scoping is enforced, not assumed. -After loading a record, call `enforceClientAccess()` (optionally with the record's client ID) so technicians restricted to specific clients cannot touch other clients' data by editing an ID in the URL. Look at how `resolve_ticket` does it — including the "skip if the record has no client" case. +A user can be restricted to a subset of clients through `user_client_permissions`. Enforcing that has two halves, and a page usually needs both. + +**One record — `enforceClientAccess()`.** After loading a record, call it (optionally with the record's client ID) so technicians restricted to specific clients cannot touch other clients' data by editing an ID in the URL. Look at how `resolve_ticket` does it. + +**A list — `clientScopeSql()`.** Any query returning more than one row appends the fragment for that resource's own client column: + +```php +$sql = mysqli_query($mysqli, "SELECT * FROM expenses + WHERE expense_archived_at IS NULL + " . clientScopeSql('expense_client_id') . " + ORDER BY expense_date DESC"); +``` + +It returns `" AND ..."` or `""`, so it needs a `WHERE` to hang off — add `WHERE 1=1` if the query has no other condition. It is column-aware and takes an alias fine (`clientScopeSql('t.ticket_client_id')`). The API calls the same helper through the `apiClientScopeSql()` wrapper. + +Scope on the resource's **own** column, not on a joined `clients.client_id`. Joining `clients` just to scope makes the filter depend on the join: with a `LEFT JOIN`, a row whose client column is `0` produces `NULL`, and `NULL IN (...)` is neither true nor false, so the row silently vanishes. If the query joins `clients` for `client_name`, keep the join for that — but still scope on the owning column. + +**Records with no client (`0`) stay visible to restricted users.** `clientScopeSql()` emits `IN (0,...)` deliberately. Client restrictions partition *client* data, and a record belonging to no client is not any client's data to withhold. Do not hand-roll a variant that drops the `0` — the tree had accumulated several before this helper existed, disagreeing with each other, and reconciling them is what surfaced the inconsistency. ### 5. Escape on output. @@ -224,6 +241,8 @@ A single update run applies every pending migration in order, stopping at the fi **After acting, log and notify.** State changes call `logAudit($type, $action, $description, $client_id, $entity_id)` for the audit trail. User-facing events may also call `appNotify()`. Fire `triggerCustomAction()` where a site might reasonably want a hook. Then call `flashAlert($message, $type)` and `redirect()` (defaults to the referer) rather than setting session keys or `header()` manually. **Function names (post-rename).** Helpers were renamed for clarity in 2026; the old names **no longer exist** — code calling them fatals. If you're rebasing an old PR or following an old tutorial, translate: `sanitizeInput` → `escapeSql`, `nullable_htmlentities` → `escapeHtml`, `logAction` → `logAudit`, `flash_alert` → `flashAlert`, `customAction` → `triggerCustomAction`, `encryptLoginEntry`/`decryptLoginEntry` → `encryptCredentialEntry`/`decryptCredentialEntry`, `strtoAZaz09` → `toAlphanumeric`, `fetchUpdates` → `checkForUpdates`, `sanitize_url` → `escapeUrl`. + +One removed **variable** deserves its own warning: the old `$access_permission_query` global is gone, replaced by `clientScopeSql()` (security rule 4). Unlike a removed function, it does not fatal — an undefined variable interpolates as an empty string, so a rebased query keeps running with **no client scoping at all**. Grep for it before rebasing anything that touches a list query. **Helpers that fetch data return it raw.** If you add a `getXById()`-style helper, return the column value untouched and let callers escape it (security rule 1). Validating what the helper interpolates into its *own* query — table and column names, the id — is still the helper's job; that is query construction, not output escaping, and the two are not the same thing. diff --git a/includes/load_user_session.php b/includes/load_user_session.php index bfd61bb96..89ee8f2e4 100644 --- a/includes/load_user_session.php +++ b/includes/load_user_session.php @@ -62,8 +62,3 @@ while ($row = mysqli_fetch_assoc($user_client_access_result)) { $client_access_array[] = (int) $row['client_id']; } } - -// Client scoping for queries is built per-query by clientScopeSql() in functions/auth.php, -// which is column-aware. These strings remain for any caller that needs the raw lists. -$client_access_string = implode(',', $client_access_array); -$client_deny_string = implode(',', $client_deny_array); From 9324d0822e3ab406b261922284fe14434485c5ee Mon Sep 17 00:00:00 2001 From: johnnyq Date: Thu, 6 Aug 2026 12:14:43 -0400 Subject: [PATCH 05/25] Drop more dead client left joins big saver is the badge counts --- agent/ajax.php | 1 - agent/invoices.php | 26 ++++++++++----------- agent/modals/asset/asset_interface_edit.php | 1 - agent/modals/ticket/ticket_sla.php | 1 - agent/post/ticket.php | 6 ----- 5 files changed, 13 insertions(+), 22 deletions(-) diff --git a/agent/ajax.php b/agent/ajax.php index afbe60d45..ea47d9809 100644 --- a/agent/ajax.php +++ b/agent/ajax.php @@ -564,7 +564,6 @@ if (isset($_POST['update_kanban_ticket'])) { // Get details $ticket_sql = mysqli_query($mysqli, "SELECT contact_name, contact_email, ticket_prefix, ticket_number, ticket_subject, ticket_status_name, ticket_assigned_to, ticket_url_key, ticket_client_id FROM tickets - LEFT JOIN clients ON ticket_client_id = client_id LEFT JOIN contacts ON ticket_contact_id = contact_id LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id WHERE ticket_id = $ticket_id diff --git a/agent/invoices.php b/agent/invoices.php index e56a96527..481ce914e 100644 --- a/agent/invoices.php +++ b/agent/invoices.php @@ -18,50 +18,50 @@ if (isset($_GET['client_id'])) { // Perms enforceUserPermission('module_sales'); -$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('invoice_id') AS num FROM invoices LEFT JOIN clients ON invoice_client_id = client_id WHERE invoice_status = 'Sent' $client_query")); +$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('invoice_id') AS num FROM invoices WHERE invoice_status = 'Sent' $client_query")); $sent_count = $row['num']; -$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('invoice_id') AS num FROM invoices LEFT JOIN clients ON invoice_client_id = client_id WHERE invoice_status = 'Viewed' $client_query")); +$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('invoice_id') AS num FROM invoices WHERE invoice_status = 'Viewed' $client_query")); $viewed_count = $row['num']; -$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('invoice_id') AS num FROM invoices LEFT JOIN clients ON invoice_client_id = client_id WHERE invoice_status = 'Partial' $client_query")); +$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('invoice_id') AS num FROM invoices WHERE invoice_status = 'Partial' $client_query")); $partial_count = $row['num']; -$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('invoice_id') AS num FROM invoices LEFT JOIN clients ON invoice_client_id = client_id WHERE invoice_status = 'Draft' $client_query")); +$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('invoice_id') AS num FROM invoices WHERE invoice_status = 'Draft' $client_query")); $draft_count = $row['num']; -$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('invoice_id') AS num FROM invoices LEFT JOIN clients ON invoice_client_id = client_id WHERE invoice_status = 'Cancelled' $client_query")); +$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('invoice_id') AS num FROM invoices WHERE invoice_status = 'Cancelled' $client_query")); $cancelled_count = $row['num']; -$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('invoice_id') AS num FROM invoices LEFT JOIN clients ON invoice_client_id = client_id WHERE invoice_status NOT LIKE 'Draft' AND invoice_status NOT LIKE 'Paid' AND invoice_status NOT LIKE 'Cancelled' AND invoice_status NOT LIKE 'Non-Billable' AND invoice_due < CURDATE() $client_query")); +$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('invoice_id') AS num FROM invoices WHERE invoice_status NOT LIKE 'Draft' AND invoice_status NOT LIKE 'Paid' AND invoice_status NOT LIKE 'Cancelled' AND invoice_status NOT LIKE 'Non-Billable' AND invoice_due < CURDATE() $client_query")); $overdue_count = $row['num']; -$sql_total_draft_amount = mysqli_query($mysqli, "SELECT SUM(invoice_amount) AS total_draft_amount FROM invoices LEFT JOIN clients ON invoice_client_id = client_id WHERE invoice_status = 'Draft' $client_query"); +$sql_total_draft_amount = mysqli_query($mysqli, "SELECT SUM(invoice_amount) AS total_draft_amount FROM invoices WHERE invoice_status = 'Draft' $client_query"); $row = mysqli_fetch_assoc($sql_total_draft_amount); $total_draft_amount = floatval($row['total_draft_amount']); -$sql_total_sent_amount = mysqli_query($mysqli, "SELECT SUM(invoice_amount) AS total_sent_amount FROM invoices LEFT JOIN clients ON invoice_client_id = client_id WHERE invoice_status = 'Sent' $client_query"); +$sql_total_sent_amount = mysqli_query($mysqli, "SELECT SUM(invoice_amount) AS total_sent_amount FROM invoices WHERE invoice_status = 'Sent' $client_query"); $row = mysqli_fetch_assoc($sql_total_sent_amount); $total_sent_amount = floatval($row['total_sent_amount']); -$sql_total_viewed_amount = mysqli_query($mysqli, "SELECT SUM(invoice_amount) AS total_viewed_amount FROM invoices LEFT JOIN clients ON invoice_client_id = client_id WHERE invoice_status = 'Viewed' $client_query"); +$sql_total_viewed_amount = mysqli_query($mysqli, "SELECT SUM(invoice_amount) AS total_viewed_amount FROM invoices WHERE invoice_status = 'Viewed' $client_query"); $row = mysqli_fetch_assoc($sql_total_viewed_amount); $total_viewed_amount = floatval($row['total_viewed_amount']); -$sql_total_cancelled_amount = mysqli_query($mysqli, "SELECT SUM(invoice_amount) AS total_cancelled_amount FROM invoices LEFT JOIN clients ON invoice_client_id = client_id WHERE invoice_status = 'Cancelled' $client_query"); +$sql_total_cancelled_amount = mysqli_query($mysqli, "SELECT SUM(invoice_amount) AS total_cancelled_amount FROM invoices WHERE invoice_status = 'Cancelled' $client_query"); $row = mysqli_fetch_assoc($sql_total_cancelled_amount); $total_cancelled_amount = floatval($row['total_cancelled_amount']); -$sql_total_partial_amount = mysqli_query($mysqli, "SELECT SUM(invoice_amount) AS total_partial_amount FROM payments, invoices LEFT JOIN clients ON invoice_client_id = client_id WHERE payment_invoice_id = invoice_id AND invoice_status = 'Partial' $client_query"); +$sql_total_partial_amount = mysqli_query($mysqli, "SELECT SUM(invoice_amount) AS total_partial_amount FROM payments, invoices WHERE payment_invoice_id = invoice_id AND invoice_status = 'Partial' $client_query"); $row = mysqli_fetch_assoc($sql_total_partial_amount); $total_partial_amount = floatval($row['total_partial_amount']); $total_partial_count = mysqli_num_rows($sql_total_partial_amount); -$sql_total_overdue_partial_amount = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS total_overdue_partial_amount FROM payments, invoices LEFT JOIN clients ON invoice_client_id = client_id WHERE payment_invoice_id = invoice_id AND invoice_status = 'Partial' AND invoice_due < CURDATE() $client_query"); +$sql_total_overdue_partial_amount = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS total_overdue_partial_amount FROM payments, invoices WHERE payment_invoice_id = invoice_id AND invoice_status = 'Partial' AND invoice_due < CURDATE() $client_query"); $row = mysqli_fetch_assoc($sql_total_overdue_partial_amount); $total_overdue_partial_amount = floatval($row['total_overdue_partial_amount']); -$sql_total_overdue_amount = mysqli_query($mysqli, "SELECT SUM(invoice_amount) AS total_overdue_amount FROM invoices LEFT JOIN clients ON invoice_client_id = client_id WHERE invoice_status != 'Draft' AND invoice_status != 'Paid' AND invoice_status != 'Cancelled' AND invoice_status != 'Non-Billable' AND invoice_due < CURDATE() $client_query"); +$sql_total_overdue_amount = mysqli_query($mysqli, "SELECT SUM(invoice_amount) AS total_overdue_amount FROM invoices WHERE invoice_status != 'Draft' AND invoice_status != 'Paid' AND invoice_status != 'Cancelled' AND invoice_status != 'Non-Billable' AND invoice_due < CURDATE() $client_query"); $row = mysqli_fetch_assoc($sql_total_overdue_amount); $total_overdue_amount = floatval($row['total_overdue_amount']); diff --git a/agent/modals/asset/asset_interface_edit.php b/agent/modals/asset/asset_interface_edit.php index 25d953c4e..131a13f73 100644 --- a/agent/modals/asset/asset_interface_edit.php +++ b/agent/modals/asset/asset_interface_edit.php @@ -6,7 +6,6 @@ $interface_id = intval($_GET['id']); $sql = mysqli_query($mysqli, "SELECT * FROM asset_interfaces LEFT JOIN assets ON asset_id = interface_asset_id - LEFT JOIN clients ON client_id = asset_client_id WHERE interface_id = $interface_id LIMIT 1" ); diff --git a/agent/modals/ticket/ticket_sla.php b/agent/modals/ticket/ticket_sla.php index 0df1de4d6..933105bbb 100644 --- a/agent/modals/ticket/ticket_sla.php +++ b/agent/modals/ticket/ticket_sla.php @@ -7,7 +7,6 @@ enforceUserPermission('module_support', 2); $ticket_id = intval($_GET['id']); $sql = mysqli_query($mysqli, "SELECT * FROM tickets - LEFT JOIN clients ON client_id = ticket_client_id WHERE ticket_id = $ticket_id LIMIT 1" ); diff --git a/agent/post/ticket.php b/agent/post/ticket.php index 4aa29c889..a371f61e5 100644 --- a/agent/post/ticket.php +++ b/agent/post/ticket.php @@ -113,7 +113,6 @@ if (isset($_POST['add_ticket'])) { // Get contact/ticket details $sql = mysqli_query($mysqli, "SELECT contact_name, contact_email, ticket_prefix, ticket_number, ticket_category, ticket_subject, ticket_details, ticket_priority, ticket_status, ticket_created_by, ticket_assigned_to, ticket_client_id FROM tickets - LEFT JOIN clients ON ticket_client_id = client_id LEFT JOIN contacts ON ticket_contact_id = contact_id WHERE ticket_id = $ticket_id"); $row = mysqli_fetch_assoc($sql); @@ -285,7 +284,6 @@ if (isset($_POST['edit_ticket'])) { // Get contact/ticket details after update for logging / email purposes $sql = mysqli_query($mysqli, "SELECT contact_name, contact_email, ticket_prefix, ticket_number, ticket_category, ticket_details, ticket_status_name, ticket_created_by, ticket_assigned_to, ticket_url_key, ticket_client_id FROM tickets - LEFT JOIN clients ON ticket_client_id = client_id LEFT JOIN contacts ON ticket_contact_id = contact_id LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id WHERE ticket_id = $ticket_id @@ -582,7 +580,6 @@ if (isset($_POST['add_ticket_watcher'])) { // Get contact/ticket details $sql = mysqli_query($mysqli, "SELECT ticket_prefix, ticket_number, ticket_category, ticket_subject, ticket_details, ticket_priority, ticket_status_name, ticket_url_key, ticket_created_by, ticket_assigned_to, ticket_client_id FROM tickets - LEFT JOIN clients ON ticket_client_id = client_id LEFT JOIN contacts ON ticket_contact_id = contact_id LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id WHERE ticket_id = $ticket_id @@ -1896,7 +1893,6 @@ if (isset($_POST['add_ticket_reply'])) { // Get Ticket Details $ticket_sql = mysqli_query($mysqli, "SELECT contact_name, contact_email, ticket_prefix, ticket_number, ticket_subject, ticket_status, ticket_status_name, ticket_url_key, ticket_first_response_at, ticket_created_by, ticket_assigned_to, ticket_client_id FROM tickets - LEFT JOIN clients ON ticket_client_id = client_id LEFT JOIN contacts ON ticket_contact_id = contact_id LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id WHERE ticket_id = $ticket_id @@ -2338,7 +2334,6 @@ if (isset($_GET['resolve_ticket'])) { // Get details $ticket_sql = mysqli_query($mysqli, "SELECT contact_name, contact_email, ticket_prefix, ticket_number, ticket_subject, ticket_status_name, ticket_assigned_to, ticket_url_key FROM tickets - LEFT JOIN clients ON ticket_client_id = client_id LEFT JOIN contacts ON ticket_contact_id = contact_id LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id WHERE ticket_id = $ticket_id @@ -2444,7 +2439,6 @@ if (isset($_GET['close_ticket'])) { // Get details $ticket_sql = mysqli_query($mysqli, "SELECT contact_name, contact_email, ticket_prefix, ticket_number, ticket_subject, ticket_url_key FROM tickets - LEFT JOIN clients ON ticket_client_id = client_id LEFT JOIN contacts ON ticket_contact_id = contact_id WHERE ticket_id = $ticket_id "); From 77defcf7d80a6307007dbebe38d0dd0034e9f7b3 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Thu, 6 Aug 2026 12:30:27 -0400 Subject: [PATCH 06/25] Global Search Query Optimization only returns columns needed --- agent/global_search.php | 53 ++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/agent/global_search.php b/agent/global_search.php index 3d5017346..bcda2362a 100644 --- a/agent/global_search.php +++ b/agent/global_search.php @@ -28,7 +28,8 @@ if (isset($_GET['query'])) { $can_sales = lookupUserPermission('module_sales') >= 1; $can_credential = lookupUserPermission('module_credential') >= 1; - $sql_clients = !$can_client ? false : mysqli_query($mysqli, "SELECT * FROM clients + $sql_clients = !$can_client ? false : mysqli_query($mysqli, "SELECT client_id, client_name, client_website, location_phone, location_phone_country_code + FROM clients LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1 WHERE client_archived_at IS NULL AND (client_name LIKE '%$query%' OR client_abbreviation LIKE '%$query%') @@ -36,7 +37,10 @@ if (isset($_GET['query'])) { ORDER BY client_id DESC LIMIT 5" ); - $sql_contacts = !$can_client ? false : mysqli_query($mysqli, "SELECT * FROM contacts + $sql_contacts = !$can_client ? false : mysqli_query($mysqli, "SELECT client_id, client_name, contact_department, contact_email, contact_extension, contact_id, + contact_mobile, contact_mobile_country_code, contact_name, contact_phone, + contact_phone_country_code, contact_title + FROM contacts LEFT JOIN clients ON client_id = contact_client_id WHERE contact_archived_at IS NULL AND (contact_name LIKE '%$query%' @@ -48,7 +52,9 @@ if (isset($_GET['query'])) { ORDER BY contact_id DESC LIMIT 5" ); - $sql_vendors = !$can_client ? false : mysqli_query($mysqli, "SELECT * FROM vendors + $sql_vendors = !$can_client ? false : mysqli_query($mysqli, "SELECT client_id, client_name, vendor_description, vendor_name, vendor_phone, + vendor_phone_country_code + FROM vendors LEFT JOIN clients ON vendor_client_id = client_id WHERE vendor_archived_at IS NULL AND (vendor_name LIKE '%$query%' OR vendor_phone LIKE '%$phone_query%') @@ -56,7 +62,8 @@ if (isset($_GET['query'])) { ORDER BY vendor_id DESC LIMIT 5" ); - $sql_domains = !$can_support ? false : mysqli_query($mysqli, "SELECT * FROM domains + $sql_domains = !$can_support ? false : mysqli_query($mysqli, "SELECT client_id, client_name, domain_expire, domain_id, domain_name + FROM domains LEFT JOIN clients ON domain_client_id = client_id WHERE domain_archived_at IS NULL AND domain_name LIKE '%$query%' @@ -64,13 +71,15 @@ if (isset($_GET['query'])) { ORDER BY domain_id DESC LIMIT 5" ); - $sql_products = !$can_sales ? false : mysqli_query($mysqli, "SELECT * FROM products + $sql_products = !$can_sales ? false : mysqli_query($mysqli, "SELECT product_description, product_name + FROM products WHERE product_archived_at IS NULL AND product_name LIKE '%$query%' ORDER BY product_id DESC LIMIT 5" ); - $sql_documents = !$can_support ? false : mysqli_query($mysqli, "SELECT * FROM documents + $sql_documents = !$can_support ? false : mysqli_query($mysqli, "SELECT client_name, document_client_id, document_id, document_name + FROM documents LEFT JOIN clients on document_client_id = clients.client_id WHERE document_archived_at IS NULL AND MATCH(document_content_raw) AGAINST ('$query') @@ -78,7 +87,8 @@ if (isset($_GET['query'])) { ORDER BY document_id DESC LIMIT 5" ); - $sql_files = !$can_support ? false : mysqli_query($mysqli, "SELECT * FROM files + $sql_files = !$can_support ? false : mysqli_query($mysqli, "SELECT client_name, file_client_id, file_description, file_id, file_name, folder_id, folder_name + FROM files LEFT JOIN clients ON file_client_id = client_id LEFT JOIN folders ON folder_id = file_folder_id WHERE file_archived_at IS NULL @@ -88,7 +98,9 @@ if (isset($_GET['query'])) { ORDER BY file_id DESC LIMIT 5" ); - $sql_tickets = !$can_support ? false : mysqli_query($mysqli, "SELECT * FROM tickets + $sql_tickets = !$can_support ? false : mysqli_query($mysqli, "SELECT client_name, ticket_client_id, ticket_id, ticket_number, ticket_prefix, ticket_status_name, + ticket_subject + FROM tickets LEFT JOIN clients on tickets.ticket_client_id = clients.client_id LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id WHERE ticket_archived_at IS NULL @@ -100,7 +112,9 @@ if (isset($_GET['query'])) { ORDER BY ticket_id DESC LIMIT 5" ); - $sql_recurring_tickets = !$can_support ? false : mysqli_query($mysqli, "SELECT * FROM recurring_tickets + $sql_recurring_tickets = !$can_support ? false : mysqli_query($mysqli, "SELECT client_id, client_name, recurring_ticket_frequency, recurring_ticket_id, + recurring_ticket_next_run, recurring_ticket_subject + FROM recurring_tickets LEFT JOIN clients ON recurring_ticket_client_id = client_id WHERE (recurring_ticket_subject LIKE '%$query%' OR recurring_ticket_details LIKE '%$query%') @@ -108,7 +122,9 @@ if (isset($_GET['query'])) { ORDER BY recurring_ticket_id DESC LIMIT 5" ); - $sql_credentials = !$can_credential ? false : mysqli_query($mysqli, "SELECT * FROM credentials + $sql_credentials = !$can_credential ? false : mysqli_query($mysqli, "SELECT client_id, client_name, credential_client_id, credential_description, credential_name, + credential_password, credential_username + FROM credentials LEFT JOIN contacts ON credential_contact_id = contact_id LEFT JOIN clients ON credential_client_id = client_id WHERE credential_archived_at IS NULL @@ -117,7 +133,9 @@ if (isset($_GET['query'])) { ORDER BY credential_id DESC LIMIT 5" ); - $sql_quotes = !$can_sales ? false : mysqli_query($mysqli, "SELECT * FROM quotes + $sql_quotes = !$can_sales ? false : mysqli_query($mysqli, "SELECT client_id, client_name, quote_amount, quote_currency_code, quote_id, quote_number, + quote_prefix, quote_status + FROM quotes LEFT JOIN clients ON quote_client_id = client_id LEFT JOIN categories ON quote_category_id = category_id WHERE quote_archived_at IS NULL @@ -126,7 +144,9 @@ if (isset($_GET['query'])) { ORDER BY quote_number DESC LIMIT 5" ); - $sql_invoices = !$can_sales ? false : mysqli_query($mysqli, "SELECT * FROM invoices + $sql_invoices = !$can_sales ? false : mysqli_query($mysqli, "SELECT client_id, client_name, invoice_amount, invoice_currency_code, invoice_id, invoice_number, + invoice_prefix, invoice_status + FROM invoices LEFT JOIN clients ON invoice_client_id = client_id LEFT JOIN categories ON invoice_category_id = category_id WHERE invoice_archived_at IS NULL @@ -135,7 +155,10 @@ if (isset($_GET['query'])) { ORDER BY invoice_number DESC LIMIT 5" ); - $sql_assets = !$can_support ? false : mysqli_query($mysqli,"SELECT * FROM assets + $sql_assets = !$can_support ? false : mysqli_query($mysqli,"SELECT asset_client_id, asset_contact_id, asset_created_at, asset_description, asset_id, + asset_location_id, asset_make, asset_model, asset_name, asset_serial, asset_status, asset_type, + asset_uri, client_name, contact_archived_at, contact_id, contact_name + FROM assets LEFT JOIN contacts ON asset_contact_id = contact_id LEFT JOIN locations ON asset_location_id = location_id LEFT JOIN clients ON asset_client_id = client_id @@ -146,7 +169,9 @@ if (isset($_GET['query'])) { ORDER BY asset_name DESC LIMIT 5" ); - $sql_ticket_replies = !$can_support ? false : mysqli_query($mysqli,"SELECT * FROM ticket_replies + $sql_ticket_replies = !$can_support ? false : mysqli_query($mysqli,"SELECT client_name, ticket_client_id, ticket_id, ticket_number, ticket_prefix, ticket_reply, + ticket_subject + FROM ticket_replies LEFT JOIN tickets ON ticket_reply_ticket_id = ticket_id LEFT JOIN clients ON ticket_client_id = client_id WHERE ticket_reply_archived_at IS NULL From b8c9d5b4cfb078588fa97b10c7c1c428223d0a48 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Thu, 6 Aug 2026 12:59:43 -0400 Subject: [PATCH 07/25] Query Optimization: Select only needed columns instead of SELECT * on looped queries --- admin/ai_models.php | 3 +- admin/audit_logs.php | 5 +-- admin/backup.php | 3 +- admin/cron.php | 2 +- admin/custom_links.php | 3 +- admin/document_templates.php | 3 +- admin/includes/side_nav.php | 2 +- admin/mail_queue.php | 3 +- .../ticket_template/ticket_template_add.php | 2 +- admin/modals/user/user_add.php | 2 +- admin/modals/user/user_edit.php | 2 +- admin/project_template.php | 6 ++-- admin/project_templates.php | 3 +- admin/settings_default.php | 8 ++--- admin/software_templates.php | 4 ++- admin/vendor_templates.php | 5 ++- agent/asset.php | 8 +++-- agent/assets.php | 9 ++++- agent/calendar.php | 23 ++++++++----- agent/certificates.php | 4 ++- agent/client_overview.php | 31 +++++++++-------- agent/contact.php | 21 ++++++++---- agent/credentials.php | 2 +- agent/dashboard.php | 8 +++-- agent/document.php | 6 ++-- agent/expenses.php | 5 ++- agent/includes/side_nav.php | 2 +- agent/invoice.php | 6 ++-- agent/invoices.php | 6 +++- agent/modals/asset/asset.php | 8 +++-- agent/modals/asset/asset_add.php | 6 ++-- agent/modals/asset/asset_bulk_add_ticket.php | 2 +- .../asset/asset_bulk_assign_contact.php | 2 +- agent/modals/asset/asset_copy.php | 8 ++--- agent/modals/asset/asset_edit.php | 8 ++--- agent/modals/asset/asset_interface_add.php | 2 +- agent/modals/calendar/calendar_event_add.php | 2 +- agent/modals/calendar/calendar_event_edit.php | 2 +- agent/modals/certificate/certificate_add.php | 2 +- agent/modals/certificate/certificate_edit.php | 3 +- .../modals/client/client_bulk_add_ticket.php | 2 +- agent/modals/contact/contact.php | 18 ++++++---- agent/modals/contact/contact_edit.php | 2 +- agent/modals/credential/credential_add.php | 4 +-- .../document/document_add_from_template.php | 2 +- agent/modals/domain/domain_add.php | 8 ++--- agent/modals/domain/domain_edit.php | 3 +- agent/modals/file/file_link_asset.php | 4 +-- agent/modals/invoice/invoice_add.php | 2 +- agent/modals/invoice/invoice_payments.php | 3 +- agent/modals/location/location_add.php | 2 +- agent/modals/location/location_edit.php | 2 +- agent/modals/network/network_add.php | 2 +- agent/modals/project/project_add.php | 4 +-- agent/modals/project/project_link_ticket.php | 2 +- agent/modals/quote/quote_add.php | 2 +- agent/modals/quote/quote_copy.php | 2 +- agent/modals/rack/rack_add.php | 2 +- agent/modals/rack/rack_device_add.php | 2 +- agent/modals/rack/rack_edit.php | 2 +- .../recurring_invoice_add.php | 2 +- .../recurring_ticket/recurring_ticket_add.php | 2 +- agent/modals/service/service.php | 10 +++--- agent/modals/service/service_add.php | 14 ++++---- agent/modals/service/service_edit.php | 14 ++++---- agent/modals/share_modal.php | 2 +- agent/modals/software/software_add.php | 4 +-- .../software/software_add_from_template.php | 2 +- agent/modals/software/software_edit.php | 4 +-- agent/modals/ticket/ticket_add.php | 2 +- agent/modals/ticket/ticket_bulk_merge.php | 2 +- agent/modals/ticket/ticket_invoice_add.php | 3 +- agent/modals/ticket/ticket_merge.php | 2 +- .../modals/transaction/transaction_export.php | 2 +- agent/modals/trip/trip_add.php | 4 +-- agent/modals/trip/trip_copy.php | 4 +-- agent/modals/trip/trip_edit.php | 6 ++-- .../vendor/vendor_add_from_template.php | 2 +- agent/modals/vendor/vendor_edit.php | 2 +- agent/networks.php | 4 ++- agent/notifications.php | 3 +- agent/post/asset.php | 2 +- agent/post/client.php | 2 +- agent/post/contact.php | 4 +-- agent/post/folder.php | 2 +- agent/post/invoice.php | 13 +++---- agent/post/quote.php | 14 ++++---- agent/post/recurring_invoice.php | 9 ++--- agent/post/ticket.php | 2 +- agent/project.php | 2 +- agent/quote.php | 3 +- agent/quotes.php | 4 ++- agent/racks.php | 4 ++- agent/recurring_expenses.php | 8 ++++- agent/recurring_invoice.php | 3 +- agent/reports/includes/reports_side_nav.php | 2 +- agent/services.php | 4 ++- agent/ticket.php | 6 ++-- agent/trips.php | 3 +- agent/vendors.php | 5 ++- api/v1/clients/archive.php | 2 +- api/v1/credentials/read.php | 2 +- client/assets.php | 4 ++- client/includes/header.php | 2 +- client/index.php | 4 +-- client/invoices.php | 3 +- client/quotes.php | 3 +- client/ticket.php | 4 ++- cron/certificate_refresher.php | 2 +- cron/mail_queue.php | 6 ++-- cron/nightly_tasks.php | 34 +++++++++++++------ guest/guest_pay_invoice_stripe.php | 2 +- guest/guest_post.php | 4 +-- guest/guest_view_invoice.php | 8 +++-- guest/guest_view_quote.php | 2 +- guest/guest_view_ticket.php | 4 ++- includes/top_nav.php | 2 +- 117 files changed, 345 insertions(+), 227 deletions(-) diff --git a/admin/ai_models.php b/admin/ai_models.php index e30dc6db3..db8f96d81 100644 --- a/admin/ai_models.php +++ b/admin/ai_models.php @@ -6,7 +6,8 @@ $order = "ASC"; require_once "includes/inc_all_admin.php"; -$sql = mysqli_query($mysqli, "SELECT * FROM ai_models LEFT JOIN ai_providers ON ai_model_ai_provider_id = ai_provider_id ORDER BY $sort $order"); +$sql = mysqli_query($mysqli, "SELECT ai_model_id, ai_model_name, ai_model_prompt, ai_model_use_case, ai_provider_id, + ai_provider_name FROM ai_models LEFT JOIN ai_providers ON ai_model_ai_provider_id = ai_provider_id ORDER BY $sort $order"); $num_rows = mysqli_num_rows($sql); diff --git a/admin/audit_logs.php b/admin/audit_logs.php index fd91cd8f6..440907e9a 100644 --- a/admin/audit_logs.php +++ b/admin/audit_logs.php @@ -48,7 +48,8 @@ if (isset($_GET['action']) & !empty($_GET['action'])) { $sql = mysqli_query( $mysqli, - "SELECT SQL_CALC_FOUND_ROWS * FROM logs + "SELECT SQL_CALC_FOUND_ROWS client_id, client_name, log_action, log_created_at, log_description, log_entity_id, log_id, + log_ip, log_type, log_user_agent, user_id, user_name FROM logs 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%') @@ -87,7 +88,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); - No - diff --git a/admin/modals/user/user_add.php b/admin/modals/user/user_add.php index e89fe85eb..b81e505dc 100644 --- a/admin/modals/user/user_add.php +++ b/admin/modals/user/user_add.php @@ -138,7 +138,7 @@ ob_start(); - None - @@ -105,7 +105,7 @@ $net_terms_array = array ( @@ -128,7 +128,7 @@ $net_terms_array = array ( @@ -153,7 +153,7 @@ $net_terms_array = array ( diff --git a/admin/software_templates.php b/admin/software_templates.php index 4672b8706..660053b01 100644 --- a/admin/software_templates.php +++ b/admin/software_templates.php @@ -8,7 +8,9 @@ require_once "includes/inc_all_admin.php"; $sql = mysqli_query( $mysqli, - "SELECT SQL_CALC_FOUND_ROWS * FROM software_templates + "SELECT SQL_CALC_FOUND_ROWS software_template_description, software_template_id, software_template_license_type, + software_template_name, software_template_notes, software_template_type, + software_template_version FROM software_templates WHERE software_template_name LIKE '%$q%' OR software_template_type LIKE '%$q%' ORDER BY $sort $order LIMIT $record_from, $record_to" ); diff --git a/admin/vendor_templates.php b/admin/vendor_templates.php index bbda9d1ef..6a58fdf5e 100644 --- a/admin/vendor_templates.php +++ b/admin/vendor_templates.php @@ -8,7 +8,10 @@ require_once "includes/inc_all_admin.php"; $sql = mysqli_query( $mysqli, - "SELECT SQL_CALC_FOUND_ROWS * FROM vendor_templates + "SELECT SQL_CALC_FOUND_ROWS vendor_template_account_number, vendor_template_code, vendor_template_contact_name, + vendor_template_description, vendor_template_email, vendor_template_extension, + vendor_template_hours, vendor_template_id, vendor_template_name, vendor_template_notes, + vendor_template_phone, vendor_template_sla, vendor_template_website FROM vendor_templates WHERE vendor_template_name LIKE '%$q%' OR vendor_template_description LIKE '%$q%' OR vendor_template_account_number LIKE '%$q%' OR vendor_template_website LIKE '%$q%' OR vendor_template_contact_name LIKE '%$q%' OR vendor_template_email LIKE '%$q%' OR vendor_template_phone LIKE '%$phone_query%' ORDER BY $sort $order LIMIT $record_from, $record_to" ); diff --git a/agent/asset.php b/agent/asset.php index e2798c31f..eb95190e7 100644 --- a/agent/asset.php +++ b/agent/asset.php @@ -206,7 +206,8 @@ if (isset($_GET['asset_id'])) { } // Related Documents - $sql_related_documents = mysqli_query($mysqli, "SELECT * FROM asset_documents, documents + $sql_related_documents = mysqli_query($mysqli, "SELECT document_created_at, document_description, documents.document_id, document_name, + document_updated_at, user_name FROM asset_documents, documents LEFT JOIN users ON document_created_by = user_id WHERE asset_documents.asset_id = $asset_id AND asset_documents.document_id = documents.document_id @@ -253,7 +254,8 @@ if (isset($_GET['asset_id'])) { $software_count = mysqli_num_rows($sql_related_software); // Linked Services - $sql_linked_services = mysqli_query($mysqli, "SELECT * FROM service_assets, services + $sql_linked_services = mysqli_query($mysqli, "SELECT service_category, service_description, service_assets.service_id, service_importance, + service_name FROM service_assets, services WHERE service_assets.asset_id = $asset_id AND service_assets.service_id = services.service_id ORDER BY service_name ASC" @@ -263,7 +265,7 @@ if (isset($_GET['asset_id'])) { $linked_services = array(); // Notes - 1 to many relationship - $sql_related_notes = mysqli_query($mysqli, "SELECT * FROM asset_notes + $sql_related_notes = mysqli_query($mysqli, "SELECT asset_note, asset_note_created_at, asset_note_id, asset_note_type, user_name FROM asset_notes LEFT JOIN users ON asset_note_created_by = user_id WHERE asset_note_asset_id = $asset_id AND asset_note_archived_at IS NULL diff --git a/agent/assets.php b/agent/assets.php index bb0d8ded4..a5bef8fa9 100644 --- a/agent/assets.php +++ b/agent/assets.php @@ -150,7 +150,14 @@ $other_count = intval($row['other_count']); $sql = mysqli_query( $mysqli, - "SELECT SQL_CALC_FOUND_ROWS * FROM assets + "SELECT SQL_CALC_FOUND_ROWS asset_archived_at, asset_contact_id, asset_created_at, asset_description, asset_favorite, + asset_id, asset_install_date, asset_location_id, asset_make, asset_model, asset_name, + asset_notes, asset_os, asset_photo, asset_physical_location, asset_purchase_date, + asset_purchase_reference, asset_serial, asset_status, asset_type, asset_uri, asset_uri_2, + asset_uri_client, asset_vendor_id, asset_warranty_expire, client_id, client_name, + contact_archived_at, contact_name, interface_ip, interface_ipv6, interface_mac, + interface_nat_ip, interface_network_id, location_archived_at, location_name, tag_color, + tag_icon, tag_id, tag_name FROM assets LEFT JOIN clients ON asset_client_id = client_id LEFT JOIN contacts ON asset_contact_id = contact_id LEFT JOIN locations ON asset_location_id = location_id diff --git a/agent/calendar.php b/agent/calendar.php index ceb20d164..08150d1f0 100644 --- a/agent/calendar.php +++ b/agent/calendar.php @@ -135,7 +135,8 @@ if (isset($_GET['calendar_id'])) { require_once "modals/calendar/calendar_event_add.php"; //loop through IDs and create a modal for each -$sql = mysqli_query($mysqli, "SELECT * FROM calendar_events LEFT JOIN calendars ON event_calendar_id = calendar_id $client_event_query"); +$sql = mysqli_query($mysqli, "SELECT calendar_color, calendar_id, calendar_name, event_client_id, event_description, event_end, + event_id, event_location, event_repeat, event_start, event_title FROM calendar_events LEFT JOIN calendars ON event_calendar_id = calendar_id $client_event_query"); while ($row = mysqli_fetch_assoc($sql)) { $event_id = intval($row['event_id']); $event_title = escapeHtml($row['event_title']); @@ -303,7 +304,8 @@ while ($row = mysqli_fetch_assoc($sql)) { }, events: [ - All Asset Locations - Revisions - +
diff --git a/agent/invoices.php b/agent/invoices.php index 481ce914e..cdaa6e600 100644 --- a/agent/invoices.php +++ b/agent/invoices.php @@ -94,7 +94,11 @@ if (isset($_GET['category']) & !empty($_GET['category'])) { $sql = mysqli_query( $mysqli, - "SELECT SQL_CALC_FOUND_ROWS * FROM invoices + "SELECT SQL_CALC_FOUND_ROWS category_id, category_name, client_currency_code, client_id, client_name, client_net_terms, + invoice_amount, invoice_created_at, invoice_currency_code, invoice_date, + invoice_discount_amount, invoice_due, invoice_id, invoice_number, invoice_prefix, + invoice_scope, invoice_status, recurring_invoice_id, recurring_invoice_number, + recurring_invoice_prefix FROM invoices LEFT JOIN clients ON invoice_client_id = client_id LEFT JOIN categories ON invoice_category_id = category_id LEFT JOIN recurring_invoices ON invoice_recurring_invoice_id = recurring_invoice_id diff --git a/agent/modals/asset/asset.php b/agent/modals/asset/asset.php index 59af1695a..772484f15 100644 --- a/agent/modals/asset/asset.php +++ b/agent/modals/asset/asset.php @@ -179,7 +179,8 @@ $sql_related_tickets = mysqli_query($mysqli, " $ticket_count = mysqli_num_rows($sql_related_tickets); // Related Recurring Tickets Query -$sql_related_recurring_tickets = mysqli_query($mysqli, "SELECT * FROM recurring_tickets +$sql_related_recurring_tickets = mysqli_query($mysqli, "SELECT recurring_ticket_frequency, recurring_ticket_assets.recurring_ticket_id, + recurring_ticket_next_run, recurring_ticket_priority, recurring_ticket_subject FROM recurring_tickets LEFT JOIN recurring_ticket_assets ON recurring_tickets.recurring_ticket_id = recurring_ticket_assets.recurring_ticket_id WHERE recurring_ticket_asset_id = $asset_id OR recurring_ticket_assets.asset_id = $asset_id GROUP BY recurring_tickets.recurring_ticket_id @@ -188,7 +189,8 @@ $sql_related_recurring_tickets = mysqli_query($mysqli, "SELECT * FROM recurring_ $recurring_ticket_count = mysqli_num_rows($sql_related_recurring_tickets); // Related Documents -$sql_related_documents = mysqli_query($mysqli, "SELECT * FROM asset_documents +$sql_related_documents = mysqli_query($mysqli, "SELECT document_created_at, document_description, documents.document_id, document_name, + document_updated_at, user_name FROM asset_documents LEFT JOIN documents ON asset_documents.document_id = documents.document_id LEFT JOIN users ON user_id = document_created_by WHERE asset_documents.asset_id = $asset_id @@ -219,7 +221,7 @@ $sql_related_software = mysqli_query( $software_count = mysqli_num_rows($sql_related_software); // Related Notes -$sql_related_notes = mysqli_query($mysqli, "SELECT * FROM asset_notes +$sql_related_notes = mysqli_query($mysqli, "SELECT asset_note, asset_note_created_at, asset_note_type, user_name FROM asset_notes LEFT JOIN users ON asset_note_created_by = user_id WHERE asset_note_asset_id = $asset_id AND asset_note_archived_at IS NULL diff --git a/agent/modals/asset/asset_add.php b/agent/modals/asset/asset_add.php index 21cf097c2..6a4a01d59 100644 --- a/agent/modals/asset/asset_add.php +++ b/agent/modals/asset/asset_add.php @@ -7,10 +7,10 @@ $contact_id = intval($_GET['contact_id'] ?? 0); $type = escapeHtml(ucwords($_GET['type']) ?? ''); if ($client_id) { - $sql_network_select = mysqli_query($mysqli, "SELECT * FROM networks WHERE network_archived_at IS NULL AND network_client_id = $client_id ORDER BY network_name ASC"); - $sql_vendor_select = mysqli_query($mysqli, "SELECT * FROM vendors WHERE vendor_archived_at IS NULL AND vendor_client_id = $client_id ORDER BY vendor_name ASC"); + $sql_network_select = mysqli_query($mysqli, "SELECT network, network_id, network_name FROM networks WHERE network_archived_at IS NULL AND network_client_id = $client_id ORDER BY network_name ASC"); + $sql_vendor_select = mysqli_query($mysqli, "SELECT vendor_id, vendor_name FROM vendors WHERE vendor_archived_at IS NULL AND vendor_client_id = $client_id ORDER BY vendor_name ASC"); $sql_location_select = mysqli_query($mysqli, "SELECT location_id, location_name FROM locations WHERE location_archived_at IS NULL AND location_client_id = $client_id ORDER BY location_name ASC"); - $sql_contact_select = mysqli_query($mysqli, "SELECT * FROM contacts WHERE contact_archived_at IS NULL AND contact_client_id = $client_id ORDER BY contact_name ASC"); + $sql_contact_select = mysqli_query($mysqli, "SELECT contact_id, contact_name FROM contacts WHERE contact_archived_at IS NULL AND contact_client_id = $client_id ORDER BY contact_name ASC"); } else { $sql_client_select = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients WHERE client_archived_at IS NULL " . clientScopeSql('clients.client_id') . " ORDER BY client_name ASC"); } diff --git a/agent/modals/asset/asset_bulk_add_ticket.php b/agent/modals/asset/asset_bulk_add_ticket.php index 9050cac8f..a1f5eed98 100644 --- a/agent/modals/asset/asset_bulk_add_ticket.php +++ b/agent/modals/asset/asset_bulk_add_ticket.php @@ -116,7 +116,7 @@ ob_start(); diff --git a/agent/modals/asset/asset_bulk_assign_contact.php b/agent/modals/asset/asset_bulk_assign_contact.php index 6d0489b76..ab301a310 100644 --- a/agent/modals/asset/asset_bulk_assign_contact.php +++ b/agent/modals/asset/asset_bulk_assign_contact.php @@ -37,7 +37,7 @@ ob_start(); - Select Location - - Select Contact - - Select Network - - Select Vendor - - Select Location - - Select Contact - - Select Network - - Select Vendor - - Client - - Client - - None - diff --git a/agent/modals/contact/contact.php b/agent/modals/contact/contact.php index 1e7941128..ba9c19444 100644 --- a/agent/modals/contact/contact.php +++ b/agent/modals/contact/contact.php @@ -52,7 +52,8 @@ $auth_method = escapeHtml($row['user_auth_method']); $contact_client_id = intval($row['contact_client_id']); // Related Assets Query - 1 to 1 relationship -$sql_related_assets = mysqli_query($mysqli, "SELECT * FROM assets +$sql_related_assets = mysqli_query($mysqli, "SELECT asset_description, asset_favorite, asset_id, asset_install_date, asset_make, asset_model, + asset_name, asset_serial, asset_status, asset_type FROM assets LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1 LEFT JOIN asset_tags ON asset_tag_asset_id = asset_id LEFT JOIN tags ON tag_id = asset_tag_tag_id @@ -63,7 +64,8 @@ $sql_related_assets = mysqli_query($mysqli, "SELECT * FROM assets $asset_count = mysqli_num_rows($sql_related_assets); // Linked Software Licenses -$sql_linked_software = mysqli_query($mysqli, "SELECT * FROM software_contacts, software +$sql_linked_software = mysqli_query($mysqli, "SELECT software.software_id, software_key, software_name, software_seats, software_type, + software_version FROM software_contacts, software WHERE software_contacts.contact_id = $contact_id AND software_contacts.software_id = software.software_id AND software_archived_at IS NULL @@ -89,7 +91,9 @@ $sql_related_credentials = mysqli_query($mysqli, " $credential_count = mysqli_num_rows($sql_related_credentials); // Related Tickets Query - 1 to 1 relationship -$sql_related_tickets = mysqli_query($mysqli, "SELECT * FROM tickets +$sql_related_tickets = mysqli_query($mysqli, "SELECT ticket_assigned_to, ticket_created_at, ticket_id, ticket_number, ticket_prefix, + ticket_priority, ticket_status, ticket_status_color, ticket_status_name, ticket_subject, + ticket_updated_at, user_name FROM tickets LEFT JOIN users ON ticket_assigned_to = user_id LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id WHERE ticket_contact_id = $contact_id @@ -98,7 +102,8 @@ $sql_related_tickets = mysqli_query($mysqli, "SELECT * FROM tickets $ticket_count = mysqli_num_rows($sql_related_tickets); // Related Recurring Tickets Query -$sql_related_recurring_tickets = mysqli_query($mysqli, "SELECT * FROM recurring_tickets +$sql_related_recurring_tickets = mysqli_query($mysqli, "SELECT recurring_ticket_frequency, recurring_ticket_next_run, recurring_ticket_priority, + recurring_ticket_subject FROM recurring_tickets WHERE recurring_ticket_contact_id = $contact_id ORDER BY recurring_ticket_next_run DESC" ); @@ -131,7 +136,7 @@ while ($row = mysqli_fetch_assoc($sql_contact_tags)) { $contact_tags_display = implode('', $contact_tag_name_display_array); // Notes - 1 to 1 relationship -$sql_related_notes = mysqli_query($mysqli, "SELECT * FROM contact_notes +$sql_related_notes = mysqli_query($mysqli, "SELECT contact_note, contact_note_created_at, contact_note_type, user_name FROM contact_notes LEFT JOIN users ON contact_note_created_by = user_id WHERE contact_note_contact_id = $contact_id AND contact_note_archived_at IS NULL @@ -156,7 +161,8 @@ $services_count = mysqli_num_rows($sql_linked_services); $linked_services = array(); // Linked Documents -$sql_linked_documents = mysqli_query($mysqli, "SELECT * FROM contact_documents, documents +$sql_linked_documents = mysqli_query($mysqli, "SELECT document_created_at, document_description, documents.document_id, document_name, + document_updated_at, user_name FROM contact_documents, documents LEFT JOIN users ON document_created_by = user_id WHERE contact_documents.contact_id = $contact_id AND contact_documents.document_id = documents.document_id diff --git a/agent/modals/contact/contact_edit.php b/agent/modals/contact/contact_edit.php index d1c5ac1f8..bd2ad1088 100644 --- a/agent/modals/contact/contact_edit.php +++ b/agent/modals/contact/contact_edit.php @@ -174,7 +174,7 @@ ob_start(); - Select Contact - - Select Asset - - Vendor - - Vendor - - Vendor - - Vendor - - Select an Asset -
- Select a Client - - Contact - - Contact - '$location_created_at' OR contact_archived_at IS NULL) AND contact_client_id = $client_id ORDER BY contact_archived_at ASC, contact_name ASC"); + $sql_contacts = mysqli_query($mysqli, "SELECT contact_archived_at, contact_id, contact_name FROM contacts WHERE (contact_archived_at > '$location_created_at' OR contact_archived_at IS NULL) AND contact_client_id = $client_id ORDER BY contact_archived_at ASC, contact_name ASC"); while ($row = mysqli_fetch_assoc($sql_contacts)) { $contact_id_select = intval($row['contact_id']); $contact_name_select = escapeHtml($row['contact_name']); diff --git a/agent/modals/network/network_add.php b/agent/modals/network/network_add.php index 67abf4cef..c5ac37f8a 100644 --- a/agent/modals/network/network_add.php +++ b/agent/modals/network/network_add.php @@ -78,7 +78,7 @@ ob_start(); Select related vendors Select related assets Select related domains '$service_created_at' OR contact_archived_at IS NULL) AND contact_client_id = $client_id"); + $sql_all = mysqli_query($mysqli, "SELECT contact_id, contact_name FROM contacts WHERE (contact_archived_at > '$service_created_at' OR contact_archived_at IS NULL) AND contact_client_id = $client_id"); while ($row_all = mysqli_fetch_assoc($sql_all)) { $contact_id = intval($row_all['contact_id']); @@ -216,7 +216,7 @@ ob_start(); '$service_created_at' OR vendor_archived_at IS NULL) AND vendor_client_id = $client_id"); + $sql_all = mysqli_query($mysqli, "SELECT vendor_id, vendor_name FROM vendors WHERE (vendor_archived_at > '$service_created_at' OR vendor_archived_at IS NULL) AND vendor_client_id = $client_id"); while ($row_all = mysqli_fetch_assoc($sql_all)) { $vendor_id = intval($row_all['vendor_id']); $vendor_name = escapeHtml($row_all['vendor_name']); @@ -238,7 +238,7 @@ ob_start(); '$service_created_at' OR asset_archived_at IS NULL) AND asset_client_id = $client_id"); + $sql_all = mysqli_query($mysqli, "SELECT asset_id, asset_name FROM assets WHERE (asset_archived_at > '$service_created_at' OR asset_archived_at IS NULL) AND asset_client_id = $client_id"); while ($row_all = mysqli_fetch_assoc($sql_all)) { $asset_id = intval($row_all['asset_id']); $asset_name = escapeHtml($row_all['asset_name']); @@ -290,7 +290,7 @@ ob_start(); '$service_created_at' OR credential_archived_at IS NULL) AND credential_client_id = $client_id"); + $sql_all = mysqli_query($mysqli, "SELECT credential_id, credential_name FROM credentials WHERE (credential_archived_at > '$service_created_at' OR credential_archived_at IS NULL) AND credential_client_id = $client_id"); while ($row_all = mysqli_fetch_assoc($sql_all)) { $credential_id = intval($row_all['credential_id']); $credential_name = escapeHtml($row_all['credential_name']); @@ -312,7 +312,7 @@ ob_start(); '$service_created_at' OR domain_archived_at IS NULL) AND domain_client_id = $client_id"); + $sql_all = mysqli_query($mysqli, "SELECT domain_id, domain_name FROM domains WHERE (domain_archived_at > '$service_created_at' OR domain_archived_at IS NULL) AND domain_client_id = $client_id"); while ($row_all = mysqli_fetch_assoc($sql_all)) { $domain_id = intval($row_all['domain_id']); $domain_name = escapeHtml($row_all['domain_name']); @@ -334,7 +334,7 @@ ob_start(); '$service_created_at' OR certificate_archived_at IS NULL) AND certificate_client_id = $client_id"); + $sql_all = mysqli_query($mysqli, "SELECT certificate_id, certificate_name FROM certificates WHERE (certificate_archived_at > '$service_created_at' OR certificate_archived_at IS NULL) AND certificate_client_id = $client_id"); while ($row_all = mysqli_fetch_assoc($sql_all)) { $cert_id = intval($row_all['certificate_id']); $cert_name = escapeHtml($row_all['certificate_name']); diff --git a/agent/modals/share_modal.php b/agent/modals/share_modal.php index eb5f9431c..eb4a86db6 100644 --- a/agent/modals/share_modal.php +++ b/agent/modals/share_modal.php @@ -28,7 +28,7 @@ '' AND contact_archived_at IS NULL ORDER BY contact_name ASC"); + $sql_client_contacts_select = mysqli_query($mysqli, "SELECT contact_email, contact_id, contact_name FROM contacts WHERE contact_client_id = $client_id AND contact_email <> '' AND contact_archived_at IS NULL ORDER BY contact_name ASC"); while ($row = mysqli_fetch_assoc($sql_client_contacts_select)) { $contact_id_select = intval($row['contact_id']); $contact_name_select = escapeHtml($row['contact_name']); diff --git a/agent/modals/software/software_add.php b/agent/modals/software/software_add.php index a5e1a0064..a79f0e783 100644 --- a/agent/modals/software/software_add.php +++ b/agent/modals/software/software_add.php @@ -244,7 +244,7 @@ ob_start(); '$software_created_at' OR asset_archived_at IS NULL) AND asset_client_id = $client_id ORDER BY asset_archived_at ASC, asset_name ASC"); + $sql_assets_select = mysqli_query($mysqli, "SELECT asset_archived_at, asset_id, asset_name, asset_type, contact_name FROM assets LEFT JOIN contacts ON asset_contact_id = contact_id WHERE (asset_archived_at > '$software_created_at' OR asset_archived_at IS NULL) AND asset_client_id = $client_id ORDER BY asset_archived_at ASC, asset_name ASC"); while ($row = mysqli_fetch_assoc($sql_assets_select)) { $asset_id_select = intval($row['asset_id']); @@ -298,7 +298,7 @@ ob_start(); '$software_created_at' OR contact_archived_at IS NULL) AND contact_client_id = $client_id ORDER BY contact_archived_at ASC, contact_name ASC"); + $sql_contacts_select = mysqli_query($mysqli, "SELECT contact_archived_at, contact_email, contact_id, contact_name FROM contacts WHERE (contact_archived_at > '$software_created_at' OR contact_archived_at IS NULL) AND contact_client_id = $client_id ORDER BY contact_archived_at ASC, contact_name ASC"); while ($row = mysqli_fetch_assoc($sql_contacts_select)) { $contact_id_select = intval($row['contact_id']); diff --git a/agent/modals/ticket/ticket_add.php b/agent/modals/ticket/ticket_add.php index d23901601..9f250c2a9 100644 --- a/agent/modals/ticket/ticket_add.php +++ b/agent/modals/ticket/ticket_add.php @@ -62,7 +62,7 @@ ob_start(); diff --git a/agent/modals/ticket/ticket_bulk_merge.php b/agent/modals/ticket/ticket_bulk_merge.php index 0558600d2..16ac34a9c 100644 --- a/agent/modals/ticket/ticket_bulk_merge.php +++ b/agent/modals/ticket/ticket_bulk_merge.php @@ -12,7 +12,7 @@ if (!empty($ticket_ids)) { $whereNotIn = "AND ticket_id NOT IN ($ids)"; } -$sql_merge = mysqli_query($mysqli, "SELECT * FROM tickets +$sql_merge = mysqli_query($mysqli, "SELECT client_name, ticket_id, ticket_number, ticket_prefix, ticket_status_name, ticket_subject FROM tickets LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id LEFT JOIN clients ON client_id = ticket_client_id WHERE ticket_closed_at IS NULL diff --git a/agent/modals/ticket/ticket_invoice_add.php b/agent/modals/ticket/ticket_invoice_add.php index 03047bf12..ae15e8174 100644 --- a/agent/modals/ticket/ticket_invoice_add.php +++ b/agent/modals/ticket/ticket_invoice_add.php @@ -81,7 +81,8 @@ $row = mysqli_fetch_assoc($ticket_total_reply_time); $ticket_total_reply_time = escapeHtml($row['ticket_total_reply_time']); $ticket_total_reply_time_display = formatDuration($ticket_total_reply_time); -$sql_invoices = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_status LIKE 'Draft' AND invoice_client_id = $client_id ORDER BY invoice_number ASC"); +$sql_invoices = mysqli_query($mysqli, "SELECT invoice_amount, invoice_date, invoice_due, invoice_id, invoice_number, invoice_prefix, + invoice_scope, invoice_status FROM invoices WHERE invoice_status LIKE 'Draft' AND invoice_client_id = $client_id ORDER BY invoice_number ASC"); ob_start(); diff --git a/agent/modals/ticket/ticket_merge.php b/agent/modals/ticket/ticket_merge.php index 0a3f0f89a..4f293bfe1 100644 --- a/agent/modals/ticket/ticket_merge.php +++ b/agent/modals/ticket/ticket_merge.php @@ -22,7 +22,7 @@ if ($client_id) { enforceClientAccess(); } -$sql_merge = mysqli_query($mysqli, "SELECT * FROM tickets +$sql_merge = mysqli_query($mysqli, "SELECT client_name, ticket_id, ticket_number, ticket_prefix, ticket_status_name, ticket_subject FROM tickets LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id LEFT JOIN clients ON client_id = ticket_client_id WHERE ticket_closed_at IS NULL diff --git a/agent/modals/transaction/transaction_export.php b/agent/modals/transaction/transaction_export.php index 1fd5ec558..ffc62e648 100644 --- a/agent/modals/transaction/transaction_export.php +++ b/agent/modals/transaction/transaction_export.php @@ -100,7 +100,7 @@ ob_start(); - Client (Optional) - - Client (Optional) - - Driver - - Client (Optional) - - None - diff --git a/agent/networks.php b/agent/networks.php index c7153bb8a..23ae73e91 100644 --- a/agent/networks.php +++ b/agent/networks.php @@ -58,7 +58,9 @@ if ($client_url && isset($_GET['location']) && !empty($_GET['location'])) { $sql = mysqli_query( $mysqli, - "SELECT SQL_CALC_FOUND_ROWS * FROM networks + "SELECT SQL_CALC_FOUND_ROWS client_id, client_name, location_name, network, network_archived_at, network_description, + network_dhcp_range, network_gateway, network_id, network_location_id, network_name, + network_primary_dns, network_secondary_dns, network_vlan FROM networks LEFT JOIN clients ON client_id = network_client_id LEFT JOIN locations ON location_id = network_location_id WHERE $archive_query diff --git a/agent/notifications.php b/agent/notifications.php index 6140d4fc8..2465833ae 100644 --- a/agent/notifications.php +++ b/agent/notifications.php @@ -18,7 +18,8 @@ if (isset($_GET['dismissed'])) { $sql = mysqli_query( $mysqli, - "SELECT SQL_CALC_FOUND_ROWS * FROM notifications + "SELECT SQL_CALC_FOUND_ROWS client_id, client_name, notification, notification_dismissed_at, notification_id, + notification_timestamp, notification_type FROM notifications LEFT JOIN clients ON notification_client_id = client_id WHERE (notification_type LIKE '%$q%' OR notification LIKE '%$q%') AND DATE(notification_timestamp) BETWEEN '$dtf' AND '$dtt' diff --git a/agent/post/asset.php b/agent/post/asset.php index 886d83b95..075ce5409 100644 --- a/agent/post/asset.php +++ b/agent/post/asset.php @@ -540,7 +540,7 @@ if (isset($_POST['bulk_transfer_client_asset'])) { $new_asset_id = mysqli_insert_id($mysqli); // Transfer all Interfaces over too - $sql_interfaces = mysqli_query($mysqli, "SELECT * FROM asset_interfaces WHERE interface_asset_id = $current_asset_id"); + $sql_interfaces = mysqli_query($mysqli, "SELECT interface_mac, interface_name, interface_primary FROM asset_interfaces WHERE interface_asset_id = $current_asset_id"); while ($row = mysqli_fetch_assoc($sql_interfaces)) { $interface_name = escapeSql($row['interface_name']); diff --git a/agent/post/client.php b/agent/post/client.php index d9fc5143a..31ae1fc77 100644 --- a/agent/post/client.php +++ b/agent/post/client.php @@ -216,7 +216,7 @@ if (isset($_GET['archive_client'])) { mysqli_query($mysqli, "UPDATE clients SET client_archived_at = NOW() WHERE client_id = $client_id"); // Stop recurring invoices - $sql_recurring_invoices = mysqli_query($mysqli, "SELECT * FROM recurring_invoices WHERE recurring_invoice_client_id = $client_id AND recurring_invoice_status = 1"); + $sql_recurring_invoices = mysqli_query($mysqli, "SELECT recurring_invoice_id FROM recurring_invoices WHERE recurring_invoice_client_id = $client_id AND recurring_invoice_status = 1"); while ($row = mysqli_fetch_assoc($sql_recurring_invoices)) { $recurring_invoice_id = intval($row['recurring_invoice_id']); mysqli_query($mysqli,"UPDATE recurring_invoices SET recurring_invoice_status = 0 WHERE recurring_invoice_id = $recurring_invoice_id AND recurring_invoice_client_id = $client_id"); diff --git a/agent/post/contact.php b/agent/post/contact.php index 16000b39d..23cff00e9 100644 --- a/agent/post/contact.php +++ b/agent/post/contact.php @@ -820,7 +820,7 @@ if (isset($_GET['anonymize_contact'])) { // Get all tickets this contact raised - $contact_tickets_sql = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_client_id = $client_id AND ticket_contact_id = $contact_id"); + $contact_tickets_sql = mysqli_query($mysqli, "SELECT ticket_details, ticket_id, ticket_subject FROM tickets WHERE ticket_client_id = $client_id AND ticket_contact_id = $contact_id"); while ($ticket = mysqli_fetch_assoc($contact_tickets_sql)) { $ticket_id = intval($ticket['ticket_id']); @@ -839,7 +839,7 @@ if (isset($_GET['anonymize_contact'])) { mysqli_query($mysqli,"UPDATE tickets SET ticket_details = '$details' WHERE ticket_id = $ticket_id"); // Redact contact name or email in the replies of all tickets they raised - $ticket_replies_sql = mysqli_query($mysqli, "SELECT * FROM ticket_replies WHERE ticket_reply_ticket_id = $ticket_id"); + $ticket_replies_sql = mysqli_query($mysqli, "SELECT ticket_reply, ticket_reply_id FROM ticket_replies WHERE ticket_reply_ticket_id = $ticket_id"); while($ticket_reply = mysqli_fetch_assoc($ticket_replies_sql)) { $ticket_reply_id = intval($ticket_reply['ticket_reply_id']); diff --git a/agent/post/folder.php b/agent/post/folder.php index d9c2ba43d..023d34247 100644 --- a/agent/post/folder.php +++ b/agent/post/folder.php @@ -78,7 +78,7 @@ if (isset($_GET['delete_folder'])) { mysqli_query($mysqli,"DELETE FROM folders WHERE folder_id = $folder_id"); // Move files in deleted folder back to the root folder / - $sql_documents = mysqli_query($mysqli,"SELECT * FROM documents WHERE document_folder_id = $folder_id"); + $sql_documents = mysqli_query($mysqli,"SELECT document_id FROM documents WHERE document_folder_id = $folder_id"); while($row = mysqli_fetch_assoc($sql_documents)) { $document_id = intval($row['document_id']); diff --git a/agent/post/invoice.php b/agent/post/invoice.php index da38550b9..c3d0b468e 100644 --- a/agent/post/invoice.php +++ b/agent/post/invoice.php @@ -74,7 +74,7 @@ if (isset($_POST['edit_invoice'])) { enforceClientAccess(); // Calculate new total - $sql = mysqli_query($mysqli,"SELECT * FROM invoice_items WHERE item_invoice_id = $invoice_id"); + $sql = mysqli_query($mysqli,"SELECT item_total FROM invoice_items WHERE item_invoice_id = $invoice_id"); $invoice_amount = 0; while($row = mysqli_fetch_assoc($sql)) { $item_total = floatval($row['item_total']); @@ -138,7 +138,8 @@ if (isset($_POST['add_invoice_copy'])) { mysqli_query($mysqli,"INSERT INTO history SET history_status = 'Draft', history_description = 'Copied INVOICE!', history_invoice_id = $new_invoice_id"); - $sql_items = mysqli_query($mysqli,"SELECT * FROM invoice_items WHERE item_invoice_id = $invoice_id"); + $sql_items = mysqli_query($mysqli,"SELECT item_description, item_id, item_name, item_order, item_price, item_quantity, item_subtotal, + item_tax, item_tax_id, item_total FROM invoice_items WHERE item_invoice_id = $invoice_id"); while($row = mysqli_fetch_assoc($sql_items)) { $item_id = intval($row['item_id']); $item_name = escapeSql($row['item_name']); @@ -271,7 +272,7 @@ if (isset($_GET['delete_invoice'])) { mysqli_query($mysqli,"DELETE FROM invoices WHERE invoice_id = $invoice_id"); //Delete Items Associated with the Invoice - $sql = mysqli_query($mysqli,"SELECT * FROM invoice_items WHERE item_invoice_id = $invoice_id"); + $sql = mysqli_query($mysqli,"SELECT item_id FROM invoice_items WHERE item_invoice_id = $invoice_id"); while($row = mysqli_fetch_assoc($sql)) { $item_id = intval($row['item_id']); mysqli_query($mysqli,"DELETE FROM invoice_items WHERE item_id = $item_id"); @@ -372,7 +373,7 @@ if (isset($_POST['add_invoice_item'])) { $invoice_discount = floatval($row['invoice_discount_amount']); //add up all line items - $sql = mysqli_query($mysqli,"SELECT * FROM invoice_items WHERE item_invoice_id = $invoice_id"); + $sql = mysqli_query($mysqli,"SELECT item_total FROM invoice_items WHERE item_invoice_id = $invoice_id"); $invoice_total = 0; while($row = mysqli_fetch_assoc($sql)) { $item_total = floatval($row['item_total']); @@ -974,7 +975,7 @@ if (isset($_GET['export_invoice_pdf'])) { $sub_total = 0; $total_tax = 0; - $sql_items = mysqli_query($mysqli, "SELECT * FROM invoice_items WHERE item_invoice_id = $invoice_id ORDER BY item_order ASC"); + $sql_items = mysqli_query($mysqli, "SELECT item_description, item_name, item_price, item_quantity, item_tax, item_total FROM invoice_items WHERE item_invoice_id = $invoice_id ORDER BY item_order ASC"); while ($item = mysqli_fetch_assoc($sql_items)) { $name = $item['item_name']; $desc = $item['item_description']; @@ -1140,7 +1141,7 @@ if (isset($_GET['export_invoice_packing_slip'])) { $sub_total = 0; $total_tax = 0; - $sql_items = mysqli_query($mysqli, "SELECT * FROM invoice_items WHERE item_invoice_id = $invoice_id ORDER BY item_order ASC"); + $sql_items = mysqli_query($mysqli, "SELECT item_name, item_quantity FROM invoice_items WHERE item_invoice_id = $invoice_id ORDER BY item_order ASC"); while ($item = mysqli_fetch_assoc($sql_items)) { $name = $item['item_name']; $qty = $item['item_quantity']; diff --git a/agent/post/quote.php b/agent/post/quote.php index 38adb631b..ef0750221 100644 --- a/agent/post/quote.php +++ b/agent/post/quote.php @@ -99,7 +99,8 @@ if (isset($_POST['add_quote_copy'])) { mysqli_query($mysqli,"INSERT INTO history SET history_status = 'Draft', history_description = 'Quote copied!', history_quote_id = $new_quote_id"); - $sql_items = mysqli_query($mysqli,"SELECT * FROM quote_items WHERE item_quote_id = $quote_id"); + $sql_items = mysqli_query($mysqli,"SELECT item_description, item_id, item_name, item_order, item_price, item_quantity, item_subtotal, + item_tax, item_tax_id, item_total FROM quote_items WHERE item_quote_id = $quote_id"); while($row = mysqli_fetch_assoc($sql_items)) { $item_id = intval($row['item_id']); $item_name = escapeSql($row['item_name']); @@ -172,7 +173,8 @@ if (isset($_POST['add_quote_to_invoice'])) { mysqli_query($mysqli,"INSERT INTO history SET history_status = 'Draft', history_description = 'Invoice created from quote $quote_prefix$quote_number', history_invoice_id = $new_invoice_id"); - $sql_items = mysqli_query($mysqli,"SELECT * FROM quote_items WHERE item_quote_id = $quote_id"); + $sql_items = mysqli_query($mysqli,"SELECT item_description, item_id, item_name, item_order, item_price, item_quantity, item_subtotal, + item_tax, item_tax_id, item_total FROM quote_items WHERE item_quote_id = $quote_id"); while($row = mysqli_fetch_assoc($sql_items)) { $item_id = intval($row['item_id']); $item_name = escapeSql($row['item_name']); @@ -260,7 +262,7 @@ if (isset($_POST['add_quote_item'])) { $client_id = intval($row['quote_client_id']); //add up the total of all items - $sql = mysqli_query($mysqli,"SELECT * FROM quote_items WHERE item_quote_id = $quote_id"); + $sql = mysqli_query($mysqli,"SELECT item_total FROM quote_items WHERE item_quote_id = $quote_id"); $quote_amount = 0; while($row = mysqli_fetch_assoc($sql)) { $item_total = floatval($row['item_total']); @@ -385,7 +387,7 @@ if (isset($_POST['edit_quote'])) { enforceClientAccess(); //Calculate the new quote amount - $sql = mysqli_query($mysqli,"SELECT * FROM quote_items WHERE item_quote_id = $quote_id"); + $sql = mysqli_query($mysqli,"SELECT item_total FROM quote_items WHERE item_quote_id = $quote_id"); $quote_amount = 0; while($row = mysqli_fetch_assoc($sql)) { $item_total = floatval($row['item_total']); @@ -423,7 +425,7 @@ if (isset($_GET['delete_quote'])) { mysqli_query($mysqli,"DELETE FROM quotes WHERE quote_id = $quote_id"); //Delete Items Associated with the Quote - $sql = mysqli_query($mysqli,"SELECT * FROM quote_items WHERE item_quote_id = $quote_id"); + $sql = mysqli_query($mysqli,"SELECT item_id FROM quote_items WHERE item_quote_id = $quote_id"); while($row = mysqli_fetch_assoc($sql)) {; $item_id = intval($row['item_id']); mysqli_query($mysqli,"DELETE FROM quote_items WHERE item_id = $item_id"); @@ -918,7 +920,7 @@ if (isset($_GET['export_quote_pdf'])) { $sub_total = 0; $total_tax = 0; - $sql_items = mysqli_query($mysqli, "SELECT * FROM quote_items WHERE item_quote_id = $quote_id ORDER BY item_order ASC"); + $sql_items = mysqli_query($mysqli, "SELECT item_description, item_name, item_price, item_quantity, item_tax, item_total FROM quote_items WHERE item_quote_id = $quote_id ORDER BY item_order ASC"); while ($item = mysqli_fetch_assoc($sql_items)) { $name = $item['item_name']; $desc = $item['item_description']; diff --git a/agent/post/recurring_invoice.php b/agent/post/recurring_invoice.php index 0f7b6d5ee..0f9b182fe 100644 --- a/agent/post/recurring_invoice.php +++ b/agent/post/recurring_invoice.php @@ -46,7 +46,8 @@ if (isset($_POST['add_invoice_recurring'])) { mysqli_query($mysqli,"INSERT INTO history SET history_status = 'Draft', history_description = 'Recurring Invoice Created from INVOICE!', history_recurring_invoice_id = $recurring_invoice_id"); - $sql_items = mysqli_query($mysqli,"SELECT * FROM invoice_items WHERE item_invoice_id = $invoice_id"); + $sql_items = mysqli_query($mysqli,"SELECT item_description, item_id, item_name, item_order, item_price, item_quantity, item_subtotal, + item_tax, item_tax_id, item_total FROM invoice_items WHERE item_invoice_id = $invoice_id"); while($row = mysqli_fetch_assoc($sql_items)) { $item_id = intval($row['item_id']); $item_name = escapeSql($row['item_name']); @@ -133,7 +134,7 @@ if (isset($_POST['edit_recurring_invoice'])) { enforceClientAccess(); //Calculate new total - $sql = mysqli_query($mysqli,"SELECT * FROM recurring_invoice_items WHERE item_recurring_invoice_id = $recurring_invoice_id"); + $sql = mysqli_query($mysqli,"SELECT item_total FROM recurring_invoice_items WHERE item_recurring_invoice_id = $recurring_invoice_id"); $recurring_invoice_amount = 0; while($row = mysqli_fetch_assoc($sql)) { $item_total = floatval($row['item_total']); @@ -174,7 +175,7 @@ if (isset($_GET['delete_recurring_invoice'])) { mysqli_query($mysqli,"DELETE FROM recurring_invoices WHERE recurring_invoice_id = $recurring_invoice_id"); //Delete Items Associated with the Recurring - $sql = mysqli_query($mysqli,"SELECT * FROM recurring_invoice_items WHERE item_recurring_invoice_id = $recurring_invoice_id"); + $sql = mysqli_query($mysqli,"SELECT item_id FROM recurring_invoice_items WHERE item_recurring_invoice_id = $recurring_invoice_id"); while($row = mysqli_fetch_assoc($sql)) { $item_id = intval($row['item_id']); mysqli_query($mysqli,"DELETE FROM recurring_invoice_items WHERE item_id = $item_id"); @@ -237,7 +238,7 @@ if (isset($_POST['add_recurring_invoice_item'])) { $client_id = intval($row['recurring_invoice_client_id']); //add up all the items - $sql = mysqli_query($mysqli,"SELECT * FROM recurring_invoice_items WHERE item_recurring_invoice_id = $recurring_invoice_id"); + $sql = mysqli_query($mysqli,"SELECT item_total FROM recurring_invoice_items WHERE item_recurring_invoice_id = $recurring_invoice_id"); $recurring_invoice_amount = 0; while($row = mysqli_fetch_assoc($sql)) { $item_total = floatval($row['item_total']); diff --git a/agent/post/ticket.php b/agent/post/ticket.php index a371f61e5..b1da09085 100644 --- a/agent/post/ticket.php +++ b/agent/post/ticket.php @@ -2996,7 +2996,7 @@ if (isset($_POST['edit_ticket_schedule'])) { //TODO make this configurable $start = date('Y-m-d H:i:s', strtotime($schedule) - 7200); $end = date('Y-m-d H:i:s', strtotime($schedule) + 7200); - $sql = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_schedule BETWEEN '$start' AND '$end' AND ticket_id != $ticket_id"); + $sql = mysqli_query($mysqli, "SELECT ticket_id, ticket_schedule, ticket_subject FROM tickets WHERE ticket_schedule BETWEEN '$start' AND '$end' AND ticket_id != $ticket_id"); if (mysqli_num_rows($sql) > 0) { $conflicting_tickets = []; while ($row = mysqli_fetch_assoc($sql)) { diff --git a/agent/project.php b/agent/project.php index c11303c98..7a5d625c9 100644 --- a/agent/project.php +++ b/agent/project.php @@ -112,7 +112,7 @@ if (isset($_GET['project_id'])) { // Get All Tasks $sql_tasks = mysqli_query($mysqli, - "SELECT * FROM tickets, tasks + "SELECT task_completed_at, task_id, task_name FROM tickets, tasks WHERE ticket_id = task_ticket_id AND ticket_project_id = $project_id ORDER BY task_created_at ASC" diff --git a/agent/quote.php b/agent/quote.php index b0bf55ab0..a5fa73a87 100644 --- a/agent/quote.php +++ b/agent/quote.php @@ -283,7 +283,8 @@ if (isset($_GET['quote_id'])) {
- +
diff --git a/agent/quotes.php b/agent/quotes.php index b86e950f1..b14379fa6 100644 --- a/agent/quotes.php +++ b/agent/quotes.php @@ -20,7 +20,9 @@ enforceUserPermission('module_sales'); $sql = mysqli_query( $mysqli, - "SELECT SQL_CALC_FOUND_ROWS * FROM quotes + "SELECT SQL_CALC_FOUND_ROWS category_id, category_name, client_currency_code, client_id, client_name, client_net_terms, + quote_amount, quote_created_at, quote_currency_code, quote_date, quote_discount_amount, + quote_expire, quote_id, quote_number, quote_prefix, quote_scope, quote_status FROM quotes LEFT JOIN clients ON quote_client_id = client_id LEFT JOIN categories ON quote_category_id = category_id WHERE (CONCAT(quote_prefix,quote_number) LIKE '%$q%' OR quote_scope LIKE '%$q%' OR category_name LIKE '%$q%' OR quote_status LIKE '%$q%' OR quote_amount LIKE '%$q%' OR client_name LIKE '%$q%') diff --git a/agent/racks.php b/agent/racks.php index 2e5cbff8a..a68f31e69 100644 --- a/agent/racks.php +++ b/agent/racks.php @@ -11,7 +11,9 @@ enforceUserPermission('module_support'); $sql = mysqli_query( $mysqli, - "SELECT SQL_CALC_FOUND_ROWS * FROM racks + "SELECT SQL_CALC_FOUND_ROWS location_name, rack_created_at, rack_depth, rack_description, rack_id, rack_location_id, + rack_model, rack_name, rack_notes, rack_photo, rack_physical_location, rack_type, + rack_units FROM racks LEFT JOIN locations ON location_id = rack_location_id WHERE rack_client_id = $client_id AND rack_$archive_query diff --git a/agent/recurring_expenses.php b/agent/recurring_expenses.php index 97daa8be9..86129b368 100644 --- a/agent/recurring_expenses.php +++ b/agent/recurring_expenses.php @@ -11,7 +11,13 @@ enforceUserPermission('module_financial'); $sql = mysqli_query( $mysqli, - "SELECT SQL_CALC_FOUND_ROWS * FROM recurring_expenses + "SELECT SQL_CALC_FOUND_ROWS account_name, category_name, client_name, recurring_expense_account_id, + recurring_expense_amount, recurring_expense_category_id, recurring_expense_client_id, + recurring_expense_created_at, recurring_expense_currency_code, recurring_expense_day, + recurring_expense_description, recurring_expense_frequency, recurring_expense_id, + recurring_expense_last_sent, recurring_expense_month, recurring_expense_next_date, + recurring_expense_payment_method, recurring_expense_reference, recurring_expense_status, + recurring_expense_vendor_id, vendor_name FROM recurring_expenses LEFT JOIN categories ON recurring_expense_category_id = category_id LEFT JOIN vendors ON recurring_expense_vendor_id = vendor_id LEFT JOIN accounts ON recurring_expense_account_id = account_id diff --git a/agent/recurring_invoice.php b/agent/recurring_invoice.php index 0ba7ea836..02028422a 100644 --- a/agent/recurring_invoice.php +++ b/agent/recurring_invoice.php @@ -252,7 +252,8 @@ if (isset($_GET['recurring_invoice_id'])) {
- +
diff --git a/agent/reports/includes/reports_side_nav.php b/agent/reports/includes/reports_side_nav.php index 364701163..2fe243bea 100644 --- a/agent/reports/includes/reports_side_nav.php +++ b/agent/reports/includes/reports_side_nav.php @@ -139,7 +139,7 @@
diff --git a/client/includes/header.php b/client/includes/header.php index 93d6851be..408faa996 100644 --- a/client/includes/header.php +++ b/client/includes/header.php @@ -80,7 +80,7 @@ header("X-Frame-Options: DENY"); // Legacy

Invoices

diff --git a/client/quotes.php b/client/quotes.php index 081da951f..b49a4efda 100644 --- a/client/quotes.php +++ b/client/quotes.php @@ -10,7 +10,8 @@ require_once "includes/inc_all.php"; enforceContactCan('accounting'); -$quotes_sql = mysqli_query($mysqli, "SELECT * FROM quotes WHERE quote_client_id = $session_client_id AND quote_status != 'Draft' ORDER BY quote_date DESC"); +$quotes_sql = mysqli_query($mysqli, "SELECT quote_amount, quote_date, quote_id, quote_number, quote_prefix, quote_scope, quote_status, + quote_url_key FROM quotes WHERE quote_client_id = $session_client_id AND quote_status != 'Draft' ORDER BY quote_date DESC"); ?>

Quotes

diff --git a/client/ticket.php b/client/ticket.php index 75bf15c17..944039085 100644 --- a/client/ticket.php +++ b/client/ticket.php @@ -269,7 +269,9 @@ if (isset($_GET['id']) && intval($_GET['id'])) {
0) { /** ======================================================================= * SEND: status = 0 (Queued) * ======================================================================= */ -$sql_queue = mysqli_query($mysqli, "SELECT * FROM email_queue WHERE email_status = 0 AND email_queued_at <= NOW()"); +$sql_queue = mysqli_query($mysqli, "SELECT email_attachments, email_cal_str, email_content, email_from, email_from_name, email_id, + email_recipient, email_recipient_name, email_subject FROM email_queue WHERE email_status = 0 AND email_queued_at <= NOW()"); if (mysqli_num_rows($sql_queue) > 0) { while ($rowq = mysqli_fetch_assoc($sql_queue)) { @@ -417,7 +418,8 @@ if (mysqli_num_rows($sql_queue) > 0) { */ $sql_failed_queue = mysqli_query( $mysqli, - "SELECT * FROM email_queue + "SELECT email_attachments, email_attempts, email_cal_str, email_content, email_from, + email_from_name, email_id, email_recipient, email_recipient_name, email_subject FROM email_queue WHERE email_status = 2 AND email_attempts < 4 AND email_failed_at <= NOW() - INTERVAL 30 MINUTE" diff --git a/cron/nightly_tasks.php b/cron/nightly_tasks.php index 997da02f9..e81a0f893 100644 --- a/cron/nightly_tasks.php +++ b/cron/nightly_tasks.php @@ -218,7 +218,7 @@ if ($config_enable_alert_domain_expire == 1) { //Get Domains Expiring $sql = mysqli_query( $mysqli, - "SELECT * FROM domains + "SELECT client_id, client_name, domain_expire, domain_id, domain_name FROM domains LEFT JOIN clients ON domain_client_id = client_id WHERE domain_expire IS NOT NULL AND domain_expire = CURDATE() + INTERVAL $day DAY" ); @@ -248,7 +248,8 @@ foreach ($certificateAlertArray as $day) { //Get Certs Expiring $sql = mysqli_query( $mysqli, - "SELECT * FROM certificates + "SELECT certificate_domain, certificate_expire, certificate_id, certificate_name, + certificate_public_key, client_id, client_name FROM certificates LEFT JOIN clients ON certificate_client_id = client_id WHERE certificate_expire = CURDATE() + INTERVAL $day DAY" ); @@ -298,7 +299,7 @@ foreach ($warranty_alert_array as $day) { //Get Asset Warranty Expiring $sql = mysqli_query( $mysqli, - "SELECT * FROM assets + "SELECT asset_id, asset_name, asset_warranty_expire, client_id, client_name FROM assets LEFT JOIN clients ON asset_client_id = client_id WHERE asset_warranty_expire = CURDATE() + INTERVAL $day DAY" ); @@ -492,7 +493,7 @@ if (mysqli_num_rows($sql_recurring_tickets) > 0) { } // Flag any active recurring "next run" dates that are in the past -$sql_invalid_recurring_tickets = mysqli_query($mysqli, "SELECT * FROM recurring_tickets WHERE recurring_ticket_next_run < CURDATE()"); +$sql_invalid_recurring_tickets = mysqli_query($mysqli, "SELECT recurring_ticket_subject FROM recurring_tickets WHERE recurring_ticket_next_run < CURDATE()"); while ($row = mysqli_fetch_assoc($sql_invalid_recurring_tickets)) { $subject = escapeSql($row['recurring_ticket_subject']); appNotify("Ticket", "Recurring ticket $subject next run date is in the past!", "/agent/recurring_tickets.php"); @@ -507,7 +508,8 @@ while ($row = mysqli_fetch_assoc($sql_invalid_recurring_tickets)) { $sql_resolved_tickets_to_close = mysqli_query( $mysqli, - "SELECT * FROM tickets + "SELECT ticket_assigned_to, ticket_client_id, ticket_id, ticket_number, ticket_prefix, + ticket_status, ticket_subject FROM tickets WHERE ticket_status = 4 AND ticket_updated_at < NOW() - INTERVAL $config_ticket_autoclose_hours HOUR" ); @@ -544,7 +546,9 @@ if ($config_send_invoice_reminders == 1) { $sql = mysqli_query( $mysqli, - "SELECT * FROM invoices + "SELECT client_id, client_name, contact_email, contact_name, invoice_amount, invoice_currency_code, + invoice_date, invoice_due, invoice_id, invoice_number, invoice_prefix, invoice_status, + invoice_url_key FROM invoices LEFT JOIN clients ON invoice_client_id = client_id LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1 WHERE invoice_status != 'Draft' @@ -702,7 +706,8 @@ while ($row = mysqli_fetch_assoc($sql_recurring_invoices)) { $new_invoice_id = mysqli_insert_id($mysqli); //Copy Items from original recurring invoice to new invoice - $sql_invoice_items = mysqli_query($mysqli, "SELECT * FROM recurring_invoice_items WHERE item_recurring_invoice_id = $recurring_invoice_id ORDER BY item_id ASC"); + $sql_invoice_items = mysqli_query($mysqli, "SELECT item_description, item_id, item_name, item_order, item_price, item_quantity, item_subtotal, + item_tax, item_tax_id, item_total FROM recurring_invoice_items WHERE item_recurring_invoice_id = $recurring_invoice_id ORDER BY item_id ASC"); while ($row = mysqli_fetch_assoc($sql_invoice_items)) { $item_id = intval($row['item_id']); @@ -812,7 +817,7 @@ while ($row = mysqli_fetch_assoc($sql_recurring_invoices)) { } //End Recurring Invoices Loop // Start Flag any active recurring "next run" dates that are in the past -$sql_invalid_recurring_invoices = mysqli_query($mysqli, "SELECT * FROM recurring_invoices WHERE recurring_invoice_next_date < CURDATE() AND recurring_invoice_status = 1"); +$sql_invalid_recurring_invoices = mysqli_query($mysqli, "SELECT recurring_invoice_number, recurring_invoice_prefix FROM recurring_invoices WHERE recurring_invoice_next_date < CURDATE() AND recurring_invoice_status = 1"); while ($row = mysqli_fetch_assoc($sql_invalid_recurring_invoices)) { $invoice_prefix = escapeSql($row['recurring_invoice_prefix']); $invoice_number = intval($row['recurring_invoice_number']); @@ -823,7 +828,10 @@ while ($row = mysqli_fetch_assoc($sql_invalid_recurring_invoices)) { // Start Recurring Payments $sql_recurring_payments = mysqli_query($mysqli, " - SELECT * FROM recurring_payments + SELECT client_id, client_name, contact_email, contact_name, invoice_amount, invoice_currency_code, + invoice_date, invoice_due, invoice_id, invoice_number, invoice_prefix, invoice_scope, + invoice_url_key, recurring_payment_account_id, recurring_payment_currency_code, + recurring_payment_method, recurring_payment_saved_payment_id FROM recurring_payments LEFT JOIN invoices ON invoice_recurring_invoice_id = recurring_payment_recurring_invoice_id LEFT JOIN clients ON client_id = invoice_client_id LEFT JOIN contacts ON client_id = contact_client_id AND contact_primary = 1 @@ -1066,7 +1074,11 @@ if ($stripe_provider) { // Recurring Expenses // Loop through all recurring expenses that match today's date and is active -$sql_recurring_expenses = mysqli_query($mysqli, "SELECT * FROM recurring_expenses WHERE recurring_expense_next_date = CURDATE() AND recurring_expense_status = 1"); +$sql_recurring_expenses = mysqli_query($mysqli, "SELECT recurring_expense_account_id, recurring_expense_amount, recurring_expense_category_id, + recurring_expense_client_id, recurring_expense_currency_code, recurring_expense_day, + recurring_expense_description, recurring_expense_frequency, recurring_expense_id, + recurring_expense_month, recurring_expense_payment_method, recurring_expense_reference, + recurring_expense_vendor_id FROM recurring_expenses WHERE recurring_expense_next_date = CURDATE() AND recurring_expense_status = 1"); while ($row = mysqli_fetch_assoc($sql_recurring_expenses)) { $recurring_expense_id = intval($row['recurring_expense_id']); @@ -1107,7 +1119,7 @@ while ($row = mysqli_fetch_assoc($sql_recurring_expenses)) { } //End Recurring expenses loop // Flag any active recurring "next run" dates that are in the past -$sql_invalid_recurring_expenses = mysqli_query($mysqli, "SELECT * FROM recurring_expenses WHERE recurring_expense_next_date < CURDATE() AND recurring_expense_status = 1"); +$sql_invalid_recurring_expenses = mysqli_query($mysqli, "SELECT recurring_expense_description FROM recurring_expenses WHERE recurring_expense_next_date < CURDATE() AND recurring_expense_status = 1"); while ($row = mysqli_fetch_assoc($sql_invalid_recurring_expenses)) { $recurring_expense_description = escapeSql($row['recurring_expense_description']); appNotify("Expense", "Recurring expense $recurring_expense_description next run date is in the past!", "/agent/recurring_expenses.php"); diff --git a/guest/guest_pay_invoice_stripe.php b/guest/guest_pay_invoice_stripe.php index 8109a55f7..bd01f16c9 100644 --- a/guest/guest_pay_invoice_stripe.php +++ b/guest/guest_pay_invoice_stripe.php @@ -62,7 +62,7 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent $balance_to_pay = round($invoice_amount - $amount_paid, 2); // Get invoice items - $sql_invoice_items = mysqli_query($mysqli, "SELECT * FROM invoice_items WHERE item_invoice_id = $invoice_id ORDER BY item_id ASC"); + $sql_invoice_items = mysqli_query($mysqli, "SELECT item_name, item_quantity, item_total FROM invoice_items WHERE item_invoice_id = $invoice_id ORDER BY item_id ASC"); // Currency formatting $currency_format = numfmt_create($company_locale, NumberFormatter::CURRENCY); diff --git a/guest/guest_post.php b/guest/guest_post.php index b23a1ae2c..ec7a02f43 100644 --- a/guest/guest_post.php +++ b/guest/guest_post.php @@ -423,7 +423,7 @@ if (isset($_GET['export_quote_pdf'])) { $sub_total = 0; $total_tax = 0; - $sql_items = mysqli_query($mysqli, "SELECT * FROM quote_items WHERE item_quote_id = $quote_id ORDER BY item_order ASC"); + $sql_items = mysqli_query($mysqli, "SELECT item_description, item_name, item_price, item_quantity, item_tax, item_total FROM quote_items WHERE item_quote_id = $quote_id ORDER BY item_order ASC"); while ($item = mysqli_fetch_assoc($sql_items)) { $name = $item['item_name']; $desc = $item['item_description']; @@ -646,7 +646,7 @@ if (isset($_GET['export_invoice_pdf'])) { $sub_total = 0; $total_tax = 0; - $sql_items = mysqli_query($mysqli, "SELECT * FROM invoice_items WHERE item_invoice_id = $invoice_id ORDER BY item_order ASC"); + $sql_items = mysqli_query($mysqli, "SELECT item_description, item_name, item_price, item_quantity, item_tax, item_total FROM invoice_items WHERE item_invoice_id = $invoice_id ORDER BY item_order ASC"); while ($item = mysqli_fetch_assoc($sql_items)) { $name = $item['item_name']; $desc = $item['item_description']; diff --git a/guest/guest_view_invoice.php b/guest/guest_view_invoice.php index f430c3d5f..993a200b6 100644 --- a/guest/guest_view_invoice.php +++ b/guest/guest_view_invoice.php @@ -135,7 +135,7 @@ if ($invoice_status !== "Paid" && $invoice_status !== "Draft" && $invoice_status } // Invoice individual items -$sql_invoice_items = mysqli_query($mysqli, "SELECT * FROM invoice_items WHERE item_invoice_id = $invoice_id ORDER BY item_order ASC"); +$sql_invoice_items = mysqli_query($mysqli, "SELECT item_description, item_id, item_name, item_price, item_quantity, item_tax, item_total FROM invoice_items WHERE item_invoice_id = $invoice_id ORDER BY item_order ASC"); // Get Total Account Balance @@ -358,7 +358,8 @@ if ($balance > 0) { // CURRENT INVOICES -$sql_current_invoices = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_client_id = $client_id AND invoice_due > CURDATE() AND(invoice_status = 'Sent' OR invoice_status = 'Viewed' OR invoice_status = 'Partial') ORDER BY invoice_number DESC"); +$sql_current_invoices = mysqli_query($mysqli, "SELECT invoice_amount, invoice_currency_code, invoice_date, invoice_due, invoice_id, + invoice_number, invoice_prefix, invoice_url_key FROM invoices WHERE invoice_client_id = $client_id AND invoice_due > CURDATE() AND(invoice_status = 'Sent' OR invoice_status = 'Viewed' OR invoice_status = 'Partial') ORDER BY invoice_number DESC"); $current_invoices_count = mysqli_num_rows($sql_current_invoices); @@ -420,7 +421,8 @@ if ($current_invoices_count > 0) { ?> // OUTSTANDING INVOICES -$sql_outstanding_invoices = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_client_id = $client_id AND invoice_due < CURDATE() AND(invoice_status = 'Sent' OR invoice_status = 'Viewed' OR invoice_status = 'Partial') ORDER BY invoice_date DESC"); +$sql_outstanding_invoices = mysqli_query($mysqli, "SELECT invoice_amount, invoice_currency_code, invoice_date, invoice_due, invoice_id, + invoice_number, invoice_prefix, invoice_url_key FROM invoices WHERE invoice_client_id = $client_id AND invoice_due < CURDATE() AND(invoice_status = 'Sent' OR invoice_status = 'Viewed' OR invoice_status = 'Partial') ORDER BY invoice_date DESC"); $outstanding_invoices_count = mysqli_num_rows($sql_outstanding_invoices); diff --git a/guest/guest_view_quote.php b/guest/guest_view_quote.php index f9ce5f4b6..f3887b784 100644 --- a/guest/guest_view_quote.php +++ b/guest/guest_view_quote.php @@ -174,7 +174,7 @@ if ($quote_status == "Draft" || $quote_status == "Sent" || $quote_status == "Vie
- +
diff --git a/guest/guest_view_ticket.php b/guest/guest_view_ticket.php index 8a5544362..b4e4e4270 100644 --- a/guest/guest_view_ticket.php +++ b/guest/guest_view_ticket.php @@ -147,7 +147,9 @@ if ($ticket_row) {
Date: Thu, 6 Aug 2026 13:10:23 -0400 Subject: [PATCH 08/25] More sweeps to replace select * with actual returned column names dramatically reduces php memory usage and speeds up processing dramatically especially in the crons since they run all the time --- admin/api_keys.php | 2 +- admin/app_logs.php | 2 +- admin/audit_logs.php | 2 +- admin/backup_download.php | 2 +- admin/categories.php | 2 +- admin/database_updates/2.3.1.php | 2 +- admin/document_template.php | 3 +- admin/modals/ai/ai_model_add.php | 2 +- admin/modals/ai/ai_model_edit.php | 4 +- admin/modals/ai/ai_provider_edit.php | 2 +- admin/modals/api/api_key_edit.php | 2 +- admin/modals/category/category_edit.php | 2 +- .../contract_template_edit.php | 8 ++- admin/modals/cron/cron_edit.php | 3 +- admin/modals/custom_link/custom_link_edit.php | 3 +- .../document_template_edit.php | 2 +- .../mail_queue/mail_queue_message_view.php | 4 +- .../payment_method/payment_method_edit.php | 2 +- .../payment_provider_edit.php | 4 +- .../project_template_edit.php | 2 +- admin/modals/role/role_add.php | 2 +- admin/modals/role/role_edit.php | 4 +- admin/modals/sla/sla_edit.php | 2 +- .../software_template_edit.php | 3 +- admin/modals/tag/tag_edit.php | 2 +- admin/modals/tax/tax_edit.php | 2 +- .../ticket_status/ticket_status_edit.php | 3 +- admin/modals/user/user_add.php | 2 +- admin/modals/user/user_archive.php | 4 +- admin/modals/user/user_edit.php | 4 +- admin/modals/user/user_restore.php | 4 +- .../vendor_template/vendor_template_edit.php | 5 +- admin/modules.php | 2 +- admin/payment_methods.php | 3 +- admin/post/users.php | 6 +-- admin/project_template.php | 3 +- admin/project_templates.php | 4 +- admin/roles.php | 2 +- admin/settings_company.php | 4 +- admin/settings_default.php | 6 +-- admin/settings_localization.php | 2 +- admin/sla.php | 3 +- admin/tags.php | 2 +- admin/tax_rates.php | 2 +- admin/ticket_statuses.php | 3 +- admin/ticket_template.php | 3 +- admin/users.php | 4 +- agent/ajax.php | 8 +-- agent/asset.php | 16 ++++-- agent/assets.php | 2 +- agent/calendar.php | 2 +- agent/client_overview.php | 5 +- agent/clients.php | 2 +- agent/contact.php | 14 +++-- agent/contacts.php | 2 +- agent/credentials.php | 5 +- agent/dashboard.php | 2 +- agent/document.php | 6 ++- agent/files.php | 6 +-- agent/includes/inc_all_client.php | 10 +++- agent/invoice.php | 16 ++++-- agent/invoices.php | 2 +- agent/locations.php | 2 +- agent/modals/account/account_edit.php | 2 +- agent/modals/asset/asset.php | 16 ++++-- agent/modals/asset/asset_bulk_assign_tags.php | 2 +- agent/modals/asset/asset_copy.php | 7 ++- agent/modals/asset/asset_edit.php | 11 ++-- agent/modals/asset/asset_interface_edit.php | 4 +- agent/modals/asset/asset_link_credential.php | 2 +- agent/modals/asset/asset_link_document.php | 2 +- agent/modals/asset/asset_link_file.php | 2 +- agent/modals/asset/asset_link_service.php | 2 +- agent/modals/asset/asset_link_software.php | 2 +- agent/modals/calendar/calendar_edit.php | 2 +- agent/modals/calendar/calendar_event_add.php | 2 +- agent/modals/calendar/calendar_event_edit.php | 5 +- agent/modals/calendar/calendar_share.php | 3 +- agent/modals/certificate/certificate_edit.php | 4 +- agent/modals/client/client_add.php | 4 +- .../modals/client/client_bulk_assign_tags.php | 2 +- .../client/client_bulk_edit_referral.php | 2 +- agent/modals/client/client_edit.php | 8 +-- agent/modals/contact/contact.php | 14 +++-- .../contact/contact_bulk_assign_tags.php | 2 +- agent/modals/contact/contact_edit.php | 8 ++- agent/modals/contact/contact_link_asset.php | 2 +- .../contact/contact_link_credential.php | 2 +- .../modals/contact/contact_link_document.php | 2 +- agent/modals/contact/contact_link_file.php | 2 +- agent/modals/contact/contact_link_service.php | 2 +- .../modals/contact/contact_link_software.php | 2 +- agent/modals/credential/credential_add.php | 2 +- .../credential_bulk_assign_tags.php | 2 +- agent/modals/credential/credential_edit.php | 5 +- .../document/document_add_file_relation.php | 2 +- .../document/document_add_from_template.php | 2 +- agent/modals/document/document_edit.php | 3 +- .../document/document_edit_visibility.php | 2 +- agent/modals/document/document_link_asset.php | 2 +- .../modals/document/document_link_contact.php | 2 +- agent/modals/document/document_link_file.php | 2 +- .../document/document_link_software.php | 2 +- .../modals/document/document_link_vendor.php | 2 +- agent/modals/document/document_move.php | 2 +- agent/modals/document/document_rename.php | 2 +- .../modals/document/document_version_view.php | 2 +- agent/modals/document/document_view.php | 2 +- agent/modals/domain/domain_edit.php | 5 +- agent/modals/expense/expense_copy.php | 4 +- agent/modals/expense/expense_edit.php | 4 +- agent/modals/expense/expense_refund.php | 4 +- agent/modals/file/file_move.php | 2 +- agent/modals/file/file_rename.php | 2 +- agent/modals/folder/folder_rename.php | 2 +- agent/modals/invoice/invoice_add.php | 2 +- agent/modals/invoice/invoice_copy.php | 2 +- agent/modals/invoice/invoice_edit.php | 5 +- agent/modals/invoice/invoice_item_edit.php | 5 +- agent/modals/invoice/invoice_payments.php | 3 +- .../modals/invoice/invoice_recurring_add.php | 2 +- agent/modals/location/location_add.php | 2 +- .../location/location_bulk_assign_tags.php | 2 +- agent/modals/location/location_edit.php | 4 +- agent/modals/network/network_edit.php | 4 +- agent/modals/payment/payment_add.php | 5 +- agent/modals/payment/payment_bulk_add.php | 4 +- agent/modals/payment/payment_edit.php | 3 +- .../payment/payment_saved_method_add.php | 4 +- agent/modals/product/product_add.php | 4 +- agent/modals/product/product_edit.php | 7 +-- agent/modals/project/project_edit.php | 4 +- .../project/project_link_closed_ticket.php | 2 +- agent/modals/project/project_link_ticket.php | 2 +- agent/modals/quote/quote_add.php | 2 +- agent/modals/quote/quote_copy.php | 2 +- agent/modals/quote/quote_edit.php | 5 +- agent/modals/quote/quote_item_edit.php | 5 +- agent/modals/quote/quote_to_invoice.php | 2 +- agent/modals/rack/rack_device_add.php | 2 +- agent/modals/rack/rack_edit.php | 4 +- .../recurring_expense_edit.php | 7 ++- .../recurring_invoice_add.php | 2 +- .../recurring_invoice_edit.php | 7 ++- .../recurring_invoice_item_edit.php | 5 +- .../recurring_ticket_edit.php | 5 +- agent/modals/revenue/revenue_add.php | 4 +- agent/modals/revenue/revenue_edit.php | 8 +-- agent/modals/service/service.php | 4 +- agent/modals/service/service_edit.php | 4 +- agent/modals/software/software_edit.php | 5 +- agent/modals/ticket/ticket_assign.php | 3 +- agent/modals/ticket/ticket_billable.php | 2 +- agent/modals/ticket/ticket_bulk_reply.php | 2 +- agent/modals/ticket/ticket_change_client.php | 2 +- agent/modals/ticket/ticket_contact.php | 2 +- agent/modals/ticket/ticket_edit.php | 5 +- agent/modals/ticket/ticket_edit_asset.php | 2 +- agent/modals/ticket/ticket_edit_project.php | 2 +- agent/modals/ticket/ticket_edit_schedule.php | 3 +- agent/modals/ticket/ticket_edit_vendor.php | 2 +- agent/modals/ticket/ticket_invoice_add.php | 11 ++-- agent/modals/ticket/ticket_merge.php | 2 +- agent/modals/ticket/ticket_priority.php | 2 +- agent/modals/ticket/ticket_quote_add.php | 9 ++-- agent/modals/ticket/ticket_reply_edit.php | 2 +- agent/modals/ticket/ticket_reply_redact.php | 2 +- agent/modals/ticket/ticket_sla.php | 2 +- .../ticket/ticket_task_approver_add.php | 2 +- agent/modals/ticket/ticket_task_edit.php | 2 +- agent/modals/transfer/transfer_add.php | 2 +- agent/modals/transfer/transfer_edit.php | 2 +- agent/modals/trip/trip_copy.php | 3 +- agent/modals/trip/trip_edit.php | 3 +- agent/modals/vendor/vendor.php | 4 +- agent/modals/vendor/vendor_edit.php | 5 +- agent/post/asset.php | 10 ++-- agent/post/client.php | 11 ++-- agent/post/contact.php | 8 +-- agent/post/credential.php | 2 +- agent/post/document.php | 5 +- agent/post/domain.php | 2 +- agent/post/event.php | 10 ++-- agent/post/expense.php | 4 +- agent/post/file.php | 4 +- agent/post/invoice.php | 52 +++++++++++++------ agent/post/location.php | 2 +- agent/post/payment.php | 22 +++++--- agent/post/project.php | 2 +- agent/post/quote.php | 52 ++++++++++++------- agent/post/recurring_invoice.php | 38 +++++++++----- agent/post/recurring_ticket.php | 14 +++-- agent/post/software.php | 3 +- agent/post/task.php | 14 ++--- agent/post/ticket.php | 32 +++++++----- agent/post/transaction.php | 2 +- agent/post/transfer.php | 2 +- agent/post/trip.php | 2 +- agent/post/vendor.php | 9 ++-- agent/project.php | 4 +- agent/quote.php | 13 +++-- agent/recurring_invoice.php | 20 +++++-- agent/recurring_invoices.php | 2 +- agent/reports/expense_summary.php | 2 +- agent/reports/income_summary.php | 2 +- agent/ticket.php | 4 +- agent/transactions.php | 2 +- agent/transfers.php | 4 +- agent/user/user_activity.php | 4 +- agent/user/user_security.php | 2 +- api/v1/assets/delete.php | 2 +- api/v1/contacts/create.php | 2 +- api/v1/contacts/delete.php | 2 +- api/v1/documents/update.php | 3 +- api/v1/tickets/resolve.php | 2 +- api/v1/validate_api_key.php | 2 +- client/includes/check_login.php | 9 ++-- client/login_microsoft.php | 2 +- client/login_reset.php | 4 +- client/post.php | 40 ++++++++------ client/recurring_invoices.php | 4 +- client/saved_payment_methods.php | 4 +- client/ticket.php | 4 +- client/unpaid_invoices.php | 6 +-- cron/backup.php | 2 +- cron/certificate_refresher.php | 2 +- cron/cron.php | 2 +- cron/domain_refresher.php | 2 +- cron/mail_queue.php | 6 ++- cron/nightly_tasks.php | 21 ++++++-- cron/ticket_email_parser.php | 6 +-- functions/app.php | 4 +- guest/guest_ajax.php | 5 +- guest/guest_approve_ticket_task.php | 3 +- guest/guest_calendar_feed.php | 2 +- guest/guest_download_file.php | 4 +- guest/guest_pay_invoice_stripe.php | 14 +++-- guest/guest_post.php | 36 ++++++++++--- guest/guest_view_invoice.php | 13 +++-- guest/guest_view_item.php | 10 ++-- guest/guest_view_quote.php | 11 +++- includes/load_company_settings.php | 2 +- includes/load_global_settings.php | 32 +++++++++++- includes/load_user_session.php | 4 +- post/misc.php | 2 +- scripts/setup_cli.php | 3 +- setup/index.php | 3 +- 247 files changed, 816 insertions(+), 457 deletions(-) diff --git a/admin/api_keys.php b/admin/api_keys.php index 1d6173b81..c0ed6cae9 100644 --- a/admin/api_keys.php +++ b/admin/api_keys.php @@ -8,7 +8,7 @@ require_once "includes/inc_all_admin.php"; $sql = mysqli_query( $mysqli, - "SELECT SQL_CALC_FOUND_ROWS * FROM api_keys + "SELECT SQL_CALC_FOUND_ROWS api_key_created_at, api_key_expire, api_key_id, api_key_name, api_key_secret, user_name FROM api_keys LEFT JOIN users on api_key_user_id = user_id WHERE (api_key_name LIKE '%$q%') ORDER BY $sort $order LIMIT $record_from, $record_to" diff --git a/admin/app_logs.php b/admin/app_logs.php index cf95b9478..2a1f7dce6 100644 --- a/admin/app_logs.php +++ b/admin/app_logs.php @@ -28,7 +28,7 @@ if (isset($_GET['category']) & !empty($_GET['catergory'])) { $sql = mysqli_query( $mysqli, - "SELECT SQL_CALC_FOUND_ROWS * FROM app_logs + "SELECT SQL_CALC_FOUND_ROWS app_log_category, app_log_created_at, app_log_details, app_log_id, app_log_type FROM app_logs WHERE (app_log_type LIKE '%$q%' OR app_log_category LIKE '%$q%' OR app_log_details LIKE '%$q%') AND DATE(app_log_created_at) BETWEEN '$dtf' AND '$dtt' $log_type_query diff --git a/admin/audit_logs.php b/admin/audit_logs.php index 440907e9a..0ce0d9709 100644 --- a/admin/audit_logs.php +++ b/admin/audit_logs.php @@ -108,7 +108,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));

Nothing to see here

Go Back"; diff --git a/admin/modals/ai/ai_model_add.php b/admin/modals/ai/ai_model_add.php index 13ea0cf95..1fe4a274b 100644 --- a/admin/modals/ai/ai_model_add.php +++ b/admin/modals/ai/ai_model_add.php @@ -26,7 +26,7 @@ ob_start(); diff --git a/agent/modals/client/client_edit.php b/agent/modals/client/client_edit.php index 175c2a56e..8336e6684 100644 --- a/agent/modals/client/client_edit.php +++ b/agent/modals/client/client_edit.php @@ -8,7 +8,9 @@ $client_id = intval($_GET['id']); enforceClientAccess(); -$sql = mysqli_query($mysqli, "SELECT * FROM clients WHERE client_id = $client_id LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT client_abbreviation, client_archived_at, client_created_at, client_lead, client_name, + client_net_terms, client_notes, client_rate, client_referral, client_tax_id_number, + client_type, client_website FROM clients WHERE client_id = $client_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $client_name = escapeHtml($row['client_name']); @@ -132,7 +134,7 @@ ob_start(); '$client_created_at' OR category_archived_at IS NULL) ORDER BY category_name ASC"); + $referral_sql = mysqli_query($mysqli, "SELECT category_name FROM categories WHERE category_type = 'Referral' AND (category_archived_at > '$client_created_at' OR category_archived_at IS NULL) ORDER BY category_name ASC"); while ($row = mysqli_fetch_assoc($referral_sql)) { $referral = escapeHtml($row['category_name']); ?> @@ -175,7 +177,7 @@ ob_start(); '$item_created_at' OR tax_archived_at IS NULL) ORDER BY tax_name ASC"); + $taxes_sql = mysqli_query($mysqli, "SELECT tax_id, tax_name, tax_percent FROM taxes WHERE (tax_archived_at > '$item_created_at' OR tax_archived_at IS NULL) ORDER BY tax_name ASC"); while ($row = mysqli_fetch_assoc($taxes_sql)) { $tax_id_select = intval($row['tax_id']); $tax_name = escapeHtml($row['tax_name']); diff --git a/agent/modals/invoice/invoice_payments.php b/agent/modals/invoice/invoice_payments.php index 1cf98eae9..db3a4f34a 100644 --- a/agent/modals/invoice/invoice_payments.php +++ b/agent/modals/invoice/invoice_payments.php @@ -6,7 +6,8 @@ enforceUserPermission('module_sales'); $invoice_id = intval($_GET['invoice_id']); -$sql = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_id = $invoice_id LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT invoice_amount, invoice_client_id, invoice_currency_code, invoice_number, invoice_prefix, + invoice_status FROM invoices WHERE invoice_id = $invoice_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $invoice_prefix = escapeHtml($row['invoice_prefix']); $invoice_number = escapeHtml($row['invoice_number']); diff --git a/agent/modals/invoice/invoice_recurring_add.php b/agent/modals/invoice/invoice_recurring_add.php index 13cd43da2..edfc1bf85 100644 --- a/agent/modals/invoice/invoice_recurring_add.php +++ b/agent/modals/invoice/invoice_recurring_add.php @@ -4,7 +4,7 @@ require_once '../../../includes/modal_header.php'; $invoice_id = intval($_GET['invoice_id']); -$sql = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_id = $invoice_id LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT invoice_client_id, invoice_number, invoice_prefix FROM invoices WHERE invoice_id = $invoice_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $invoice_prefix = escapeHtml($row['invoice_prefix']); diff --git a/agent/modals/location/location_add.php b/agent/modals/location/location_add.php index d56ac6583..2f4dd74c3 100644 --- a/agent/modals/location/location_add.php +++ b/agent/modals/location/location_add.php @@ -246,7 +246,7 @@ ob_start(); '$item_created_at' OR tax_archived_at IS NULL) ORDER BY tax_name ASC"); + $taxes_sql = mysqli_query($mysqli, "SELECT tax_id, tax_name, tax_percent FROM taxes WHERE (tax_archived_at > '$item_created_at' OR tax_archived_at IS NULL) ORDER BY tax_name ASC"); while ($row = mysqli_fetch_assoc($taxes_sql)) { $tax_id_select = intval($row['tax_id']); $tax_name = escapeHtml($row['tax_name']); diff --git a/agent/modals/quote/quote_to_invoice.php b/agent/modals/quote/quote_to_invoice.php index 21d6a1412..6aed5fa3c 100644 --- a/agent/modals/quote/quote_to_invoice.php +++ b/agent/modals/quote/quote_to_invoice.php @@ -6,7 +6,7 @@ enforceUserPermission('module_sales', 2); $quote_id = intval($_GET['quote_id']); -$sql = mysqli_query($mysqli, "SELECT * FROM quotes WHERE quote_id = $quote_id LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT quote_client_id, quote_number, quote_prefix FROM quotes WHERE quote_id = $quote_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $quote_prefix = escapeHtml($row['quote_prefix']); diff --git a/agent/modals/rack/rack_device_add.php b/agent/modals/rack/rack_device_add.php index 860a6b0e2..0ef99ad86 100644 --- a/agent/modals/rack/rack_device_add.php +++ b/agent/modals/rack/rack_device_add.php @@ -4,7 +4,7 @@ require_once '../../../includes/modal_header.php'; $rack_id = intval($_GET['id']); -$sql = mysqli_query($mysqli, "SELECT * FROM racks WHERE rack_id = $rack_id LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT rack_client_id, rack_name FROM racks WHERE rack_id = $rack_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $rack_name = escapeHtml($row['rack_name']); diff --git a/agent/modals/rack/rack_edit.php b/agent/modals/rack/rack_edit.php index 1cf1732b7..f0cf435ed 100644 --- a/agent/modals/rack/rack_edit.php +++ b/agent/modals/rack/rack_edit.php @@ -6,7 +6,9 @@ enforceUserPermission('module_support', 2); $rack_id = intval($_GET['id']); -$sql = mysqli_query($mysqli, "SELECT * FROM racks WHERE rack_id = $rack_id LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT rack_client_id, rack_created_at, rack_depth, rack_description, rack_location_id, + rack_model, rack_name, rack_notes, rack_photo, rack_physical_location, rack_type, + rack_units FROM racks WHERE rack_id = $rack_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $rack_name = escapeHtml($row['rack_name']); diff --git a/agent/modals/recurring_expense/recurring_expense_edit.php b/agent/modals/recurring_expense/recurring_expense_edit.php index 9ffc7c441..92033284d 100644 --- a/agent/modals/recurring_expense/recurring_expense_edit.php +++ b/agent/modals/recurring_expense/recurring_expense_edit.php @@ -6,7 +6,12 @@ enforceUserPermission('module_financial', 2); $recurring_expense_id = intval($_GET['id']); -$sql = mysqli_query($mysqli, "SELECT * FROM recurring_expenses WHERE recurring_expense_id = $recurring_expense_id LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT recurring_expense_account_id, recurring_expense_amount, recurring_expense_category_id, + recurring_expense_client_id, recurring_expense_created_at, recurring_expense_currency_code, + recurring_expense_day, recurring_expense_description, recurring_expense_frequency, + recurring_expense_last_sent, recurring_expense_month, recurring_expense_next_date, + recurring_expense_payment_method, recurring_expense_reference, recurring_expense_status, + recurring_expense_vendor_id FROM recurring_expenses WHERE recurring_expense_id = $recurring_expense_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $recurring_expense_frequency = intval($row['recurring_expense_frequency']); diff --git a/agent/modals/recurring_invoice/recurring_invoice_add.php b/agent/modals/recurring_invoice/recurring_invoice_add.php index 0099a9a7c..54e4ffb38 100644 --- a/agent/modals/recurring_invoice/recurring_invoice_add.php +++ b/agent/modals/recurring_invoice/recurring_invoice_add.php @@ -92,7 +92,7 @@ ob_start(); - Category - '$recurring_invoice_created_at' OR category_archived_at IS NULL) ORDER BY category_name ASC"); + $sql_income_category = mysqli_query($mysqli, "SELECT category_id, category_name FROM categories WHERE category_type = 'Income' AND (category_archived_at > '$recurring_invoice_created_at' OR category_archived_at IS NULL) ORDER BY category_name ASC"); while ($row = mysqli_fetch_assoc($sql_income_category)) { $category_id_select = intval($row['category_id']); $category_name_select = escapeHtml($row['category_name']); diff --git a/agent/modals/recurring_invoice/recurring_invoice_item_edit.php b/agent/modals/recurring_invoice/recurring_invoice_item_edit.php index 756598c51..98165ce05 100644 --- a/agent/modals/recurring_invoice/recurring_invoice_item_edit.php +++ b/agent/modals/recurring_invoice/recurring_invoice_item_edit.php @@ -6,7 +6,8 @@ enforceUserPermission('module_sales', 2); $item_id = intval($_GET['id']); -$sql = mysqli_query($mysqli, "SELECT * FROM recurring_invoice_items LEFT JOIN recurring_invoices ON recurring_invoice_id = item_recurring_invoice_id WHERE item_id = $item_id LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT item_created_at, item_description, item_name, item_price, item_product_id, item_quantity, + item_tax_id, recurring_invoice_client_id FROM recurring_invoice_items LEFT JOIN recurring_invoices ON recurring_invoice_id = item_recurring_invoice_id WHERE item_id = $item_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $item_name = escapeHtml($row['item_name']); $item_description = escapeHtml($row['item_description']); @@ -87,7 +88,7 @@ ob_start(); - diff --git a/agent/modals/ticket/ticket_change_client.php b/agent/modals/ticket/ticket_change_client.php index 1e7a7141e..2d570be0c 100644 --- a/agent/modals/ticket/ticket_change_client.php +++ b/agent/modals/ticket/ticket_change_client.php @@ -6,7 +6,7 @@ enforceUserPermission('module_support', 2); $ticket_id = intval($_GET['ticket_id']); -$sql = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = $ticket_id LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT ticket_client_id, ticket_number, ticket_prefix FROM tickets WHERE ticket_id = $ticket_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $ticket_prefix = escapeHtml($row['ticket_prefix']); diff --git a/agent/modals/ticket/ticket_contact.php b/agent/modals/ticket/ticket_contact.php index ff1a94a26..e72ccc797 100644 --- a/agent/modals/ticket/ticket_contact.php +++ b/agent/modals/ticket/ticket_contact.php @@ -6,7 +6,7 @@ enforceUserPermission('module_support', 2); $ticket_id = intval($_GET['id']); -$sql = mysqli_query($mysqli, "SELECT * FROM tickets +$sql = mysqli_query($mysqli, "SELECT client_name, ticket_client_id, ticket_contact_id, ticket_number, ticket_prefix FROM tickets LEFT JOIN clients ON client_id = ticket_client_id WHERE ticket_id = $ticket_id LIMIT 1" diff --git a/agent/modals/ticket/ticket_edit.php b/agent/modals/ticket/ticket_edit.php index fa0535755..5a3b6b042 100644 --- a/agent/modals/ticket/ticket_edit.php +++ b/agent/modals/ticket/ticket_edit.php @@ -9,7 +9,10 @@ $access_permission_query_overide = clientScopeSql('ticket_client_id'); $ticket_id = intval($_GET['id']); -$sql = mysqli_query($mysqli, "SELECT * FROM tickets LEFT JOIN clients ON client_id = ticket_client_id WHERE ticket_id = $ticket_id $access_permission_query_overide LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT client_id, client_name, ticket_asset_id, ticket_assigned_to, ticket_billable, + ticket_category, ticket_contact_id, ticket_created_at, ticket_details, ticket_due_at, + ticket_location_id, ticket_number, ticket_prefix, ticket_priority, ticket_project_id, + ticket_subject, ticket_vendor_id, ticket_vendor_ticket_number FROM tickets LEFT JOIN clients ON client_id = ticket_client_id WHERE ticket_id = $ticket_id $access_permission_query_overide LIMIT 1"); $row = mysqli_fetch_assoc($sql); $client_id = intval($row['client_id']); diff --git a/agent/modals/ticket/ticket_edit_asset.php b/agent/modals/ticket/ticket_edit_asset.php index d9c75caa8..3644db2da 100644 --- a/agent/modals/ticket/ticket_edit_asset.php +++ b/agent/modals/ticket/ticket_edit_asset.php @@ -6,7 +6,7 @@ enforceUserPermission('module_support', 2); $ticket_id = intval($_GET['id']); -$sql = mysqli_query($mysqli, "SELECT * FROM tickets LEFT JOIN clients ON client_id = ticket_client_id WHERE ticket_id = $ticket_id LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT client_name, ticket_asset_id, ticket_client_id, ticket_number, ticket_prefix FROM tickets LEFT JOIN clients ON client_id = ticket_client_id WHERE ticket_id = $ticket_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $client_name = escapeHtml($row['client_name']); diff --git a/agent/modals/ticket/ticket_edit_project.php b/agent/modals/ticket/ticket_edit_project.php index d3880e04d..0fcc89c75 100644 --- a/agent/modals/ticket/ticket_edit_project.php +++ b/agent/modals/ticket/ticket_edit_project.php @@ -6,7 +6,7 @@ enforceUserPermission('module_support', 2); $ticket_id = intval($_GET['id']); -$sql = mysqli_query($mysqli, "SELECT * FROM tickets LEFT JOIN clients ON client_id = ticket_client_id WHERE ticket_id = $ticket_id LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT client_name, ticket_client_id, ticket_number, ticket_prefix, ticket_project_id FROM tickets LEFT JOIN clients ON client_id = ticket_client_id WHERE ticket_id = $ticket_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $client_name = escapeHtml($row['client_name']); diff --git a/agent/modals/ticket/ticket_edit_schedule.php b/agent/modals/ticket/ticket_edit_schedule.php index 579001886..ebb7d6cb1 100644 --- a/agent/modals/ticket/ticket_edit_schedule.php +++ b/agent/modals/ticket/ticket_edit_schedule.php @@ -6,7 +6,8 @@ enforceUserPermission('module_support', 2); $ticket_id = intval($_GET['ticket_id']); -$sql = mysqli_query($mysqli, "SELECT * FROM tickets +$sql = mysqli_query($mysqli, "SELECT client_name, ticket_client_id, ticket_number, ticket_onsite, ticket_prefix, + ticket_schedule FROM tickets LEFT JOIN clients ON client_id = ticket_client_id WHERE ticket_id = $ticket_id LIMIT 1" diff --git a/agent/modals/ticket/ticket_edit_vendor.php b/agent/modals/ticket/ticket_edit_vendor.php index f9bbc0e1a..33ce877e0 100644 --- a/agent/modals/ticket/ticket_edit_vendor.php +++ b/agent/modals/ticket/ticket_edit_vendor.php @@ -6,7 +6,7 @@ enforceUserPermission('module_support', 2); $ticket_id = intval($_GET['ticket_id']); -$sql = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = $ticket_id LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT ticket_client_id, ticket_number, ticket_prefix, ticket_vendor_id FROM tickets WHERE ticket_id = $ticket_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $ticket_prefix = escapeHtml($row['ticket_prefix']); diff --git a/agent/modals/ticket/ticket_invoice_add.php b/agent/modals/ticket/ticket_invoice_add.php index ae15e8174..f8118cebd 100644 --- a/agent/modals/ticket/ticket_invoice_add.php +++ b/agent/modals/ticket/ticket_invoice_add.php @@ -6,7 +6,12 @@ $ticket_id = intval($_GET['ticket_id']); $ticket_sql = mysqli_query( $mysqli, - "SELECT * FROM tickets + "SELECT asset_id, asset_name, asset_type, category_name, client_id, client_rate, contact_id, + contact_name, location_address, location_city, location_id, location_name, location_phone, + location_state, location_zip, ticket_assigned_to, ticket_billable, ticket_category, + ticket_created_at, ticket_created_by, ticket_first_response_at, ticket_number, + ticket_onsite, ticket_prefix, ticket_priority, ticket_quote_id, ticket_resolved_at, + ticket_subject, user_name FROM tickets LEFT JOIN clients ON ticket_client_id = client_id LEFT JOIN contacts ON ticket_contact_id = contact_id LEFT JOIN users ON ticket_assigned_to = user_id @@ -184,7 +189,7 @@ ob_start(); None - Method of Transfer - diff --git a/agent/modals/transfer/transfer_edit.php b/agent/modals/transfer/transfer_edit.php index 4a525f07d..c1f948de1 100644 --- a/agent/modals/transfer/transfer_edit.php +++ b/agent/modals/transfer/transfer_edit.php @@ -169,7 +169,7 @@ ob_start(); diff --git a/agent/modals/trip/trip_copy.php b/agent/modals/trip/trip_copy.php index 082629296..2a25b36e7 100644 --- a/agent/modals/trip/trip_copy.php +++ b/agent/modals/trip/trip_copy.php @@ -6,7 +6,8 @@ enforceUserPermission('module_financial', 2); $trip_id = intval($_GET['id']); -$sql = mysqli_query($mysqli, "SELECT * FROM trips WHERE trip_id = $trip_id LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT round_trip, trip_archived_at, trip_client_id, trip_created_at, trip_date, trip_destination, + trip_miles, trip_purpose, trip_source, trip_user_id FROM trips WHERE trip_id = $trip_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $trip_date = escapeHtml($row['trip_date']); diff --git a/agent/modals/trip/trip_edit.php b/agent/modals/trip/trip_edit.php index 51c97f80e..53275cf7b 100644 --- a/agent/modals/trip/trip_edit.php +++ b/agent/modals/trip/trip_edit.php @@ -6,7 +6,8 @@ enforceUserPermission('module_financial', 2); $trip_id = intval($_GET['id']); -$sql = mysqli_query($mysqli, "SELECT * FROM trips WHERE trip_id = $trip_id LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT round_trip, trip_archived_at, trip_client_id, trip_created_at, trip_date, trip_destination, + trip_miles, trip_purpose, trip_source, trip_user_id FROM trips WHERE trip_id = $trip_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $trip_date = escapeHtml($row['trip_date']); diff --git a/agent/modals/vendor/vendor.php b/agent/modals/vendor/vendor.php index c4a7f98ae..79039f7c7 100644 --- a/agent/modals/vendor/vendor.php +++ b/agent/modals/vendor/vendor.php @@ -6,7 +6,9 @@ enforceUserPermission('module_client'); $vendor_id = intval($_GET['id']); -$sql = mysqli_query($mysqli, "SELECT * FROM vendors WHERE vendor_id = $vendor_id LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT vendor_account_number, vendor_client_id, vendor_code, vendor_contact_name, + vendor_description, vendor_email, vendor_extension, vendor_hours, vendor_name, + vendor_notes, vendor_phone, vendor_sla, vendor_website FROM vendors WHERE vendor_id = $vendor_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $name = escapeHtml($row['vendor_name']); diff --git a/agent/modals/vendor/vendor_edit.php b/agent/modals/vendor/vendor_edit.php index 823116600..e79768fd1 100644 --- a/agent/modals/vendor/vendor_edit.php +++ b/agent/modals/vendor/vendor_edit.php @@ -6,7 +6,10 @@ enforceUserPermission('module_client', 2); $vendor_id = intval($_GET['id']); -$sql = mysqli_query($mysqli, "SELECT * FROM vendors WHERE vendor_id = $vendor_id LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT vendor_account_number, vendor_client_id, vendor_code, vendor_contact_name, + vendor_description, vendor_email, vendor_extension, vendor_hours, vendor_name, + vendor_notes, vendor_phone, vendor_phone_country_code, vendor_sla, vendor_template_id, + vendor_website FROM vendors WHERE vendor_id = $vendor_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $vendor_name = escapeHtml($row['vendor_name']); diff --git a/agent/post/asset.php b/agent/post/asset.php index 075ce5409..73d0919e6 100644 --- a/agent/post/asset.php +++ b/agent/post/asset.php @@ -387,7 +387,7 @@ if (isset($_POST['bulk_assign_asset_tags'])) { foreach($_POST['tags'] as $tag) { $tag = intval($tag); - $sql = mysqli_query($mysqli,"SELECT * FROM asset_tags WHERE asset_tag_asset_id = $asset_id AND asset_tag_tag_id = $tag"); + $sql = mysqli_query($mysqli,"SELECT 1 FROM asset_tags WHERE asset_tag_asset_id = $asset_id AND asset_tag_tag_id = $tag"); if (mysqli_num_rows($sql) == 0) { mysqli_query($mysqli, "INSERT INTO asset_tags SET asset_tag_asset_id = $asset_id, asset_tag_tag_id = $tag"); } @@ -1224,7 +1224,7 @@ if (isset($_POST["import_assets_csv"])) { if (!empty($column[8])) { $contact = escapeSql($column[8]); if ($contact) { - $sql_contact = mysqli_query($mysqli,"SELECT * FROM contacts WHERE contact_name = '$contact' AND contact_client_id = $client_id"); + $sql_contact = mysqli_query($mysqli,"SELECT contact_id FROM contacts WHERE contact_name = '$contact' AND contact_client_id = $client_id"); $row = mysqli_fetch_assoc($sql_contact); $contact_id = intval($row['contact_id']); } @@ -1234,7 +1234,7 @@ if (isset($_POST["import_assets_csv"])) { if (!empty($column[9])) { $location = escapeSql($column[9]); if ($location) { - $sql_location = mysqli_query($mysqli,"SELECT * FROM locations WHERE location_name = '$location' AND location_client_id = $client_id"); + $sql_location = mysqli_query($mysqli,"SELECT location_id FROM locations WHERE location_name = '$location' AND location_client_id = $client_id"); $row = mysqli_fetch_assoc($sql_location); $location_id = intval($row['location_id']); } @@ -1911,7 +1911,7 @@ if (isset($_POST["import_client_asset_interfaces_csv"])) { $file_name = $_FILES["file"]["tmp_name"]; // Get Asset Details for logging - $sql_asset = mysqli_query($mysqli,"SELECT * FROM assets WHERE asset_id = $asset_id"); + $sql_asset = mysqli_query($mysqli,"SELECT asset_client_id, asset_name FROM assets WHERE asset_id = $asset_id"); $row = mysqli_fetch_assoc($sql_asset); $client_id = intval($row['asset_client_id']); $asset_name = escapeSql($row['asset_name']); @@ -1989,7 +1989,7 @@ if (isset($_POST["import_client_asset_interfaces_csv"])) { if (!empty($column[7])) { $network = escapeSql($column[7]); if ($network) { - $sql_network = mysqli_query($mysqli,"SELECT * FROM networks WHERE network_name = '$network' AND network_archived_at IS NULL AND network_client_id = $client_id"); + $sql_network = mysqli_query($mysqli,"SELECT network_id FROM networks WHERE network_name = '$network' AND network_archived_at IS NULL AND network_client_id = $client_id"); $row = mysqli_fetch_assoc($sql_network); $network_id = intval($row['network_id']); } diff --git a/agent/post/client.php b/agent/post/client.php index 31ae1fc77..bff9b2dee 100644 --- a/agent/post/client.php +++ b/agent/post/client.php @@ -741,7 +741,7 @@ if (isset($_POST['bulk_add_client_ticket'])) { // Check to see if adding a ticket by template if($ticket_template_id) { - $sql = mysqli_query($mysqli, "SELECT * FROM ticket_templates WHERE ticket_template_id = $ticket_template_id"); + $sql = mysqli_query($mysqli, "SELECT ticket_template_details, ticket_template_subject FROM ticket_templates WHERE ticket_template_id = $ticket_template_id"); $row = mysqli_fetch_assoc($sql); // Override Template Subject @@ -751,7 +751,7 @@ if (isset($_POST['bulk_add_client_ticket'])) { $details = mysqli_escape_string($mysqli, $row['ticket_template_details']); // Get Associated Tasks from the ticket template - $sql_task_templates = mysqli_query($mysqli, "SELECT * FROM task_templates WHERE task_template_ticket_template_id = $ticket_template_id"); + $sql_task_templates = mysqli_query($mysqli, "SELECT task_template_name, task_template_order FROM task_templates WHERE task_template_ticket_template_id = $ticket_template_id"); } @@ -764,7 +764,7 @@ if (isset($_POST['bulk_add_client_ticket'])) { foreach ($_POST['client_ids'] as $client_id) { $client_id = intval($client_id); - $sql = mysqli_query($mysqli, "SELECT * FROM clients WHERE client_id = $client_id"); + $sql = mysqli_query($mysqli, "SELECT client_name FROM clients WHERE client_id = $client_id"); $row = mysqli_fetch_assoc($sql); $client_name = escapeSql($row['client_name']); @@ -992,7 +992,7 @@ if (isset($_POST['bulk_assign_client_tags'])) { foreach($_POST['bulk_tags'] as $tag) { $tag = intval($tag); - $sql = mysqli_query($mysqli,"SELECT * FROM client_tags WHERE client_id = $client_id AND tag_id = $tag"); + $sql = mysqli_query($mysqli,"SELECT 1 FROM client_tags WHERE client_id = $client_id AND tag_id = $tag"); if (mysqli_num_rows($sql) == 0) { mysqli_query($mysqli, "INSERT INTO client_tags SET client_id = $client_id, tag_id = $tag"); } @@ -1181,7 +1181,8 @@ if (isset($_POST["export_client_pdf"])) { enforceUserPermission("module_sales", 1); enforceUserPermission("module_financial", 1); - $sql = mysqli_query($mysqli, "SELECT * FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1"); + $sql = mysqli_query($mysqli, "SELECT company_email, company_logo, company_name, company_phone, company_phone_country_code, + company_website FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1"); $row = mysqli_fetch_assoc($sql); $company_name = escapeHtml($row['company_name']); $company_phone_country_code = escapeHtml($row['company_phone_country_code']); diff --git a/agent/post/contact.php b/agent/post/contact.php index 23cff00e9..ad1ff20cb 100644 --- a/agent/post/contact.php +++ b/agent/post/contact.php @@ -544,7 +544,7 @@ if (isset($_POST['bulk_assign_contact_tags'])) { foreach($_POST['bulk_tags'] as $tag) { $tag = intval($tag); - $sql = mysqli_query($mysqli,"SELECT * FROM contact_tags WHERE contact_id = $contact_id AND tag_id = $tag"); + $sql = mysqli_query($mysqli,"SELECT 1 FROM contact_tags WHERE contact_id = $contact_id AND tag_id = $tag"); if (mysqli_num_rows($sql) == 0) { mysqli_query($mysqli, "INSERT INTO contact_tags SET contact_id = $contact_id, tag_id = $tag"); } @@ -584,7 +584,7 @@ if (isset($_POST['send_bulk_mail_now'])) { foreach($_POST['contact_ids'] as $contact_id) { $contact_id = intval($contact_id); - $sql = mysqli_query($mysqli,"SELECT * FROM contacts WHERE contact_id = $contact_id"); + $sql = mysqli_query($mysqli,"SELECT contact_client_id, contact_email, contact_name FROM contacts WHERE contact_id = $contact_id"); $row = mysqli_fetch_assoc($sql); $contact_name = escapeSql($row['contact_name']); $contact_email = escapeSql($row['contact_email']); @@ -808,7 +808,7 @@ if (isset($_GET['anonymize_contact'])) { // Redact audit logs - $log_sql = mysqli_query($mysqli, "SELECT * FROM logs WHERE log_client_id = $client_id"); + $log_sql = mysqli_query($mysqli, "SELECT log_description, log_id FROM logs WHERE log_client_id = $client_id"); while ($log = mysqli_fetch_assoc($log_sql)) { $log_id = intval($log['log_id']); $description = $log['log_description']; @@ -1452,7 +1452,7 @@ if (isset($_POST["import_contacts_csv"])) { } if (isset($column[7])) { $location = escapeSql($column[7]); - $sql_location = mysqli_query($mysqli,"SELECT * FROM locations WHERE location_name = '$location' AND location_client_id = $client_id"); + $sql_location = mysqli_query($mysqli,"SELECT location_id FROM locations WHERE location_name = '$location' AND location_client_id = $client_id"); $row = mysqli_fetch_assoc($sql_location); $location_id = intval($row['location_id']); } diff --git a/agent/post/credential.php b/agent/post/credential.php index 22bfa502e..024d62a9d 100644 --- a/agent/post/credential.php +++ b/agent/post/credential.php @@ -194,7 +194,7 @@ if (isset($_POST['bulk_assign_credential_tags'])) { foreach($_POST['bulk_tags'] as $tag) { $tag = intval($tag); - $sql = mysqli_query($mysqli,"SELECT * FROM credential_tags WHERE credential_id = $credential_id AND tag_id = $tag"); + $sql = mysqli_query($mysqli,"SELECT 1 FROM credential_tags WHERE credential_id = $credential_id AND tag_id = $tag"); if (mysqli_num_rows($sql) == 0) { mysqli_query($mysqli, "INSERT INTO credential_tags SET credential_id = $credential_id, tag_id = $tag"); } diff --git a/agent/post/document.php b/agent/post/document.php index de29e063a..4d039bc16 100644 --- a/agent/post/document.php +++ b/agent/post/document.php @@ -70,7 +70,7 @@ if (isset($_POST['add_document_from_template'])) { // Get template $sql_document = mysqli_query( $mysqli, - "SELECT * FROM document_templates + "SELECT document_template_content, document_template_name FROM document_templates WHERE document_template_id = $document_template_id" ); @@ -154,7 +154,8 @@ if (isset($_POST['edit_document'])) { // 1) Load the current document to create a version $sql_original_document = mysqli_query( $mysqli, - "SELECT * FROM documents + "SELECT document_content, document_created_at, document_created_by, document_description, + document_name, document_updated_at, document_updated_by FROM documents WHERE document_client_id = $client_id AND document_id = $document_id" ); diff --git a/agent/post/domain.php b/agent/post/domain.php index 782674ecb..60adc8a43 100644 --- a/agent/post/domain.php +++ b/agent/post/domain.php @@ -207,7 +207,7 @@ if (isset($_GET['archive_domain'])) { $domain_id = intval($_GET['archive_domain']); //Get domain Name - $sql = mysqli_query($mysqli,"SELECT * FROM domains WHERE domain_id = $domain_id"); + $sql = mysqli_query($mysqli,"SELECT domain_client_id, domain_name FROM domains WHERE domain_id = $domain_id"); $row = mysqli_fetch_assoc($sql); $domain_name = escapeSql($row['domain_name']); $client_id = intval($row['domain_client_id']); diff --git a/agent/post/event.php b/agent/post/event.php index 449de8673..e1b9044f4 100644 --- a/agent/post/event.php +++ b/agent/post/event.php @@ -50,7 +50,7 @@ if (isset($_GET['delete_calendar'])) { $calendar_id = intval($_GET['delete_calendar']); // Get Calendar Name - $sql = mysqli_query($mysqli,"SELECT * FROM calendars WHERE calendar_id = $calendar_id"); + $sql = mysqli_query($mysqli,"SELECT calendar_name FROM calendars WHERE calendar_id = $calendar_id"); $row = mysqli_fetch_assoc($sql); $calendar_name = escapeSql($row['calendar_name']); @@ -192,7 +192,8 @@ if (isset($_POST['add_event'])) { $contact_name = escapeSql($row['contact_name']); $contact_email = escapeSql($row['contact_email']); - $sql_company = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1"); + $sql_company = mysqli_query($mysqli,"SELECT company_address, company_city, company_country, company_email, company_logo, company_name, + company_phone, company_state, company_website, company_zip FROM companies WHERE company_id = 1"); $row = mysqli_fetch_assoc($sql_company); $company_name = escapeSql($row['company_name']); $company_country = escapeSql($row['company_country']); @@ -266,7 +267,8 @@ if (isset($_POST['edit_event'])) { $contact_name = escapeSql($row['contact_name']); $contact_email = escapeSql($row['contact_email']); - $sql_company = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1"); + $sql_company = mysqli_query($mysqli,"SELECT company_address, company_city, company_country, company_email, company_logo, company_name, + company_phone, company_state, company_website, company_zip FROM companies WHERE company_id = 1"); $row = mysqli_fetch_assoc($sql_company); $company_name = escapeSql($row['company_name']); $company_country = escapeSql($row['company_country']); @@ -323,7 +325,7 @@ if (isset($_GET['delete_event'])) { $event_id = intval($_GET['delete_event']); // Get Event Title - $sql = mysqli_query($mysqli,"SELECT * FROM calendar_events WHERE event_id = $event_id"); + $sql = mysqli_query($mysqli,"SELECT event_client_id, event_title FROM calendar_events WHERE event_id = $event_id"); $row = mysqli_fetch_assoc($sql); $event_title = escapeSql($row['event_title']); $client_id = intval($row['event_client_id']); diff --git a/agent/post/expense.php b/agent/post/expense.php index a547dffcc..ce269108e 100644 --- a/agent/post/expense.php +++ b/agent/post/expense.php @@ -104,7 +104,7 @@ if (isset($_GET['delete_expense'])) { $expense_id = intval($_GET['delete_expense']); - $sql = mysqli_query($mysqli,"SELECT * FROM expenses WHERE expense_id = $expense_id"); + $sql = mysqli_query($mysqli,"SELECT expense_client_id, expense_description, expense_receipt FROM expenses WHERE expense_id = $expense_id"); $row = mysqli_fetch_assoc($sql); $expense_receipt = escapeSql($row['expense_receipt']); $expense_description = escapeSql($row['expense_description']); @@ -270,7 +270,7 @@ if (isset($_POST['bulk_delete_expenses'])) { $expense_id = intval($expense_id); - $sql = mysqli_query($mysqli,"SELECT * FROM expenses WHERE expense_id = $expense_id"); + $sql = mysqli_query($mysqli,"SELECT expense_client_id, expense_description, expense_receipt FROM expenses WHERE expense_id = $expense_id"); $row = mysqli_fetch_assoc($sql); $expense_description = escapeSql($row['expense_description']); $expense_receipt = escapeSql($row['expense_receipt']); diff --git a/agent/post/file.php b/agent/post/file.php index 5005f274c..f2d656e34 100644 --- a/agent/post/file.php +++ b/agent/post/file.php @@ -267,7 +267,7 @@ if (isset($_POST['bulk_archive_files'])) { $file_id = intval($file_id); - $sql_file = mysqli_query($mysqli,"SELECT * FROM files WHERE file_id = $file_id"); + $sql_file = mysqli_query($mysqli,"SELECT file_client_id, file_name FROM files WHERE file_id = $file_id"); $row = mysqli_fetch_assoc($sql_file); $client_id = intval($row['file_client_id']); $file_name = escapeSql($row['file_name']); @@ -411,7 +411,7 @@ if (isset($_POST['bulk_restore_files'])) { $file_id = intval($file_id); - $sql_file = mysqli_query($mysqli,"SELECT * FROM files WHERE file_id = $file_id"); + $sql_file = mysqli_query($mysqli,"SELECT file_client_id, file_name FROM files WHERE file_id = $file_id"); $row = mysqli_fetch_assoc($sql_file); $client_id = intval($row['file_client_id']); $file_name = escapeSql($row['file_name']); diff --git a/agent/post/invoice.php b/agent/post/invoice.php index c3d0b468e..3c5975966 100644 --- a/agent/post/invoice.php +++ b/agent/post/invoice.php @@ -103,7 +103,9 @@ if (isset($_POST['add_invoice_copy'])) { $date = escapeSql($_POST['date']); //Get Net Terms - $sql = mysqli_query($mysqli,"SELECT * FROM clients, invoices WHERE client_id = invoice_client_id AND invoice_id = $invoice_id"); + $sql = mysqli_query($mysqli,"SELECT client_net_terms, invoice_amount, invoice_category_id, invoice_client_id, + invoice_currency_code, invoice_discount_amount, invoice_note, invoice_number, + invoice_prefix, invoice_scope FROM clients, invoices WHERE client_id = invoice_client_id AND invoice_id = $invoice_id"); $row = mysqli_fetch_assoc($sql); $client_net_terms = intval($row['client_net_terms']); $invoice_scope = escapeSql($row['invoice_scope']); @@ -279,14 +281,14 @@ if (isset($_GET['delete_invoice'])) { } //Delete History Associated with the Invoice - $sql = mysqli_query($mysqli,"SELECT * FROM history WHERE history_invoice_id = $invoice_id"); + $sql = mysqli_query($mysqli,"SELECT history_id FROM history WHERE history_invoice_id = $invoice_id"); while($row = mysqli_fetch_assoc($sql)) { $history_id = intval($row['history_id']); mysqli_query($mysqli,"DELETE FROM history WHERE history_id = $history_id"); } //Delete Payments Associated with the Invoice - $sql = mysqli_query($mysqli,"SELECT * FROM payments WHERE payment_invoice_id = $invoice_id"); + $sql = mysqli_query($mysqli,"SELECT payment_id FROM payments WHERE payment_invoice_id = $invoice_id"); while($row = mysqli_fetch_assoc($sql)) { $payment_id = intval($row['payment_id']); mysqli_query($mysqli,"DELETE FROM payments WHERE payment_id = $payment_id"); @@ -353,7 +355,7 @@ if (isset($_POST['add_invoice_item'])) { // Tax if ($tax_id > 0) { - $sql = mysqli_query($mysqli,"SELECT * FROM taxes WHERE tax_id = $tax_id"); + $sql = mysqli_query($mysqli,"SELECT tax_percent FROM taxes WHERE tax_id = $tax_id"); $row = mysqli_fetch_assoc($sql); $tax_percent = floatval($row['tax_percent']); $tax_amount = $subtotal * $tax_percent / 100; @@ -366,7 +368,7 @@ if (isset($_POST['add_invoice_item'])) { mysqli_query($mysqli,"INSERT INTO invoice_items SET item_name = '$name', item_description = '$description', item_quantity = $qty, item_price = $price, item_subtotal = $subtotal, item_tax = $tax_amount, item_total = $total, item_order = $item_order, item_tax_id = $tax_id, item_product_id = $product_id, item_invoice_id = $invoice_id"); // Get Discount and Invoice Details - $sql = mysqli_query($mysqli,"SELECT * FROM invoices WHERE invoice_id = $invoice_id"); + $sql = mysqli_query($mysqli,"SELECT invoice_discount_amount, invoice_number, invoice_prefix FROM invoices WHERE invoice_id = $invoice_id"); $row = mysqli_fetch_assoc($sql); $invoice_prefix = escapeSql($row['invoice_prefix']); $invoice_number = intval($row['invoice_number']); @@ -401,7 +403,7 @@ if (isset($_POST['invoice_note'])) { $note = escapeSql($_POST['note']); // Get Invoice Details for logging - $sql = mysqli_query($mysqli,"SELECT * FROM invoices WHERE invoice_id = $invoice_id"); + $sql = mysqli_query($mysqli,"SELECT invoice_client_id, invoice_number, invoice_prefix FROM invoices WHERE invoice_id = $invoice_id"); $row = mysqli_fetch_assoc($sql); $invoice_prefix = escapeSql($row['invoice_prefix']); $invoice_number = intval($row['invoice_number']); @@ -436,7 +438,7 @@ if (isset($_POST['edit_invoice_item'])) { $subtotal = $price * $qty; if ($tax_id > 0) { - $sql = mysqli_query($mysqli,"SELECT * FROM taxes WHERE tax_id = $tax_id"); + $sql = mysqli_query($mysqli,"SELECT tax_percent FROM taxes WHERE tax_id = $tax_id"); $row = mysqli_fetch_assoc($sql); $tax_percent = floatval($row['tax_percent']); $tax_amount = $subtotal * $tax_percent / 100; @@ -452,7 +454,7 @@ if (isset($_POST['edit_invoice_item'])) { $invoice_id = intval($row['item_invoice_id']); //Get Discount Amount - $sql = mysqli_query($mysqli,"SELECT * FROM invoices WHERE invoice_id = $invoice_id"); + $sql = mysqli_query($mysqli,"SELECT invoice_client_id, invoice_discount_amount, invoice_number, invoice_prefix FROM invoices WHERE invoice_id = $invoice_id"); $row = mysqli_fetch_assoc($sql); $invoice_prefix = escapeSql($row['invoice_prefix']); $invoice_number = intval($row['invoice_number']); @@ -486,7 +488,8 @@ if (isset($_GET['delete_invoice_item'])) { $item_id = intval($_GET['delete_invoice_item']); - $sql = mysqli_query($mysqli,"SELECT * FROM invoice_items WHERE item_id = $item_id"); + $sql = mysqli_query($mysqli,"SELECT item_invoice_id, item_name, item_product_id, item_quantity, item_subtotal, item_tax, + item_total FROM invoice_items WHERE item_id = $item_id"); $row = mysqli_fetch_assoc($sql); $invoice_id = intval($row['item_invoice_id']); $item_name = escapeSql($row['item_name']); @@ -496,7 +499,7 @@ if (isset($_GET['delete_invoice_item'])) { $item_tax = floatval($row['item_tax']); $item_total = floatval($row['item_total']); - $sql = mysqli_query($mysqli,"SELECT * FROM invoices WHERE invoice_id = $invoice_id"); + $sql = mysqli_query($mysqli,"SELECT invoice_amount, invoice_client_id, invoice_number, invoice_prefix FROM invoices WHERE invoice_id = $invoice_id"); $row = mysqli_fetch_assoc($sql); $invoice_prefix = escapeSql($row['invoice_prefix']); $invoice_number = intval($row['invoice_number']); @@ -531,7 +534,9 @@ if (isset($_GET['email_invoice'])) { $invoice_id = intval($_GET['email_invoice']); - $sql = mysqli_query($mysqli,"SELECT * FROM invoices + $sql = mysqli_query($mysqli,"SELECT client_id, client_name, contact_email, contact_name, invoice_amount, invoice_currency_code, + invoice_date, invoice_due, invoice_id, invoice_number, invoice_prefix, invoice_scope, + invoice_status, invoice_url_key FROM invoices LEFT JOIN clients ON invoice_client_id = client_id LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1 WHERE invoice_id = $invoice_id" @@ -555,7 +560,8 @@ if (isset($_GET['email_invoice'])) { enforceClientAccess(); - $sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1"); + $sql = mysqli_query($mysqli,"SELECT company_address, company_city, company_country, company_email, company_logo, company_name, + company_phone, company_phone_country_code, company_state, company_website, company_zip FROM companies WHERE company_id = 1"); $row = mysqli_fetch_assoc($sql); $company_name = escapeSql($row['company_name']); @@ -819,7 +825,13 @@ if (isset($_GET['export_invoice_pdf'])) { $sql = mysqli_query( $mysqli, - "SELECT * FROM invoices + "SELECT client_currency_code, client_id, client_name, client_net_terms, client_website, + contact_email, contact_extension, contact_mobile, contact_mobile_country_code, + contact_phone, contact_phone_country_code, invoice_amount, invoice_category_id, + invoice_created_at, invoice_currency_code, invoice_date, invoice_discount_amount, + invoice_due, invoice_id, invoice_note, invoice_number, invoice_prefix, invoice_scope, + invoice_status, invoice_url_key, location_address, location_city, location_country, + location_state, location_zip FROM invoices LEFT JOIN clients ON invoice_client_id = client_id LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1 LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1 @@ -865,7 +877,9 @@ if (isset($_GET['export_invoice_pdf'])) { enforceClientAccess(); - $sql = mysqli_query($mysqli, "SELECT * FROM companies WHERE company_id = 1"); + $sql = mysqli_query($mysqli, "SELECT company_address, company_city, company_country, company_email, company_id, company_logo, + company_name, company_phone, company_phone_country_code, company_state, company_tax_id, + company_website, company_zip FROM companies WHERE company_id = 1"); $row = mysqli_fetch_assoc($sql); $company_id = intval($row['company_id']); $company_name = escapeHtml($row['company_name']); @@ -1048,7 +1062,9 @@ if (isset($_GET['export_invoice_packing_slip'])) { $sql = mysqli_query( $mysqli, - "SELECT * FROM invoices + "SELECT client_id, client_name, contact_email, contact_extension, contact_phone, + contact_phone_country_code, invoice_date, invoice_id, invoice_number, invoice_prefix, + location_address, location_city, location_country, location_state, location_zip FROM invoices LEFT JOIN clients ON invoice_client_id = client_id LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1 LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1 @@ -1076,7 +1092,9 @@ if (isset($_GET['export_invoice_packing_slip'])) { enforceClientAccess(); - $sql = mysqli_query($mysqli, "SELECT * FROM companies WHERE company_id = 1"); + $sql = mysqli_query($mysqli, "SELECT company_address, company_city, company_country, company_email, company_id, company_logo, + company_name, company_phone, company_phone_country_code, company_state, company_website, + company_zip FROM companies WHERE company_id = 1"); $row = mysqli_fetch_assoc($sql); $company_id = intval($row['company_id']); $company_name = escapeHtml($row['company_name']); @@ -1206,7 +1224,7 @@ if (isset($_POST['bulk_edit_invoice_category'])) { $invoice_id = intval($invoice_id); // Get Invoice Details for Logging - $sql = mysqli_query($mysqli,"SELECT * FROM invoices WHERE invoice_id = $invoice_id"); + $sql = mysqli_query($mysqli,"SELECT invoice_client_id, invoice_number, invoice_prefix, invoice_scope FROM invoices WHERE invoice_id = $invoice_id"); $row = mysqli_fetch_assoc($sql); $invoice_prefix = escapeSql($row['invoice_prefix']); $invoice_number = intval($row['invoice_number']); diff --git a/agent/post/location.php b/agent/post/location.php index 47773a8ba..6f4cb07cc 100644 --- a/agent/post/location.php +++ b/agent/post/location.php @@ -242,7 +242,7 @@ if (isset($_POST['bulk_assign_location_tags'])) { foreach($_POST['bulk_tags'] as $tag) { $tag = intval($tag); - $sql = mysqli_query($mysqli,"SELECT * FROM location_tags WHERE location_id = $location_id AND tag_id = $tag"); + $sql = mysqli_query($mysqli,"SELECT 1 FROM location_tags WHERE location_id = $location_id AND tag_id = $tag"); if (mysqli_num_rows($sql) == 0) { mysqli_query($mysqli, "INSERT INTO location_tags SET location_id = $location_id, tag_id = $tag"); } diff --git a/agent/post/payment.php b/agent/post/payment.php index 4c4a79647..83c2c2996 100644 --- a/agent/post/payment.php +++ b/agent/post/payment.php @@ -43,7 +43,9 @@ if (isset($_POST['add_payment'])) { $total_payments_amount = floatval($row['payments_amount']); //Get the invoice total - $sql = mysqli_query($mysqli,"SELECT * FROM invoices + $sql = mysqli_query($mysqli,"SELECT client_name, contact_email, contact_extension, contact_mobile, contact_mobile_country_code, + contact_name, contact_phone, contact_phone_country_code, invoice_amount, + invoice_currency_code, invoice_number, invoice_prefix, invoice_url_key FROM invoices LEFT JOIN clients ON invoice_client_id = client_id LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1 WHERE invoice_id = $invoice_id" @@ -62,7 +64,8 @@ if (isset($_POST['add_payment'])) { $contact_extension = preg_replace("/[^0-9]/", '',$row['contact_extension']); $contact_mobile = escapeSql(formatPhoneNumber($row['contact_mobile'], $row['contact_mobile_country_code'])); - $sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1"); + $sql = mysqli_query($mysqli,"SELECT company_address, company_city, company_country, company_email, company_logo, company_name, + company_phone, company_phone_country_code, company_state, company_website, company_zip FROM companies WHERE company_id = 1"); $row = mysqli_fetch_assoc($sql); $company_name = escapeSql($row['company_name']); @@ -218,7 +221,7 @@ if (isset($_POST['apply_credit'])) { $invoice_id = intval($_POST['invoice_id']); $credit_amount_applied = floatval($_POST['credit_amount_applied']); - $sql = mysqli_query($mysqli, "SELECT * FROM invoices LEFT JOIN clients ON invoice_client_id = client_id WHERE invoice_id = $invoice_id"); + $sql = mysqli_query($mysqli, "SELECT invoice_client_id, invoice_credit_amount, invoice_number, invoice_prefix, invoice_status FROM invoices LEFT JOIN clients ON invoice_client_id = client_id WHERE invoice_id = $invoice_id"); $row = mysqli_fetch_assoc($sql); $invoice_prefix = escapeSql($row['invoice_prefix']); @@ -329,7 +332,10 @@ if (isset($_POST['add_payment_stripe'])) { $saved_payment_id = intval($_POST['saved_payment_id']); // Get invoice details - $sql = mysqli_query($mysqli,"SELECT * FROM invoices + $sql = mysqli_query($mysqli,"SELECT client_id, client_name, contact_email, contact_extension, contact_mobile, + contact_mobile_country_code, contact_name, contact_phone, contact_phone_country_code, + invoice_amount, invoice_currency_code, invoice_number, invoice_prefix, invoice_status, + invoice_url_key FROM invoices LEFT JOIN clients ON invoice_client_id = client_id LEFT JOIN contacts ON client_id = contact_client_id AND contact_primary = 1 WHERE invoice_id = $invoice_id" @@ -353,7 +359,8 @@ if (isset($_POST['add_payment_stripe'])) { enforceClientAccess(); // Get ITFlow company details - $sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1"); + $sql = mysqli_query($mysqli,"SELECT company_address, company_city, company_country, company_email, company_name, company_phone, + company_phone_country_code, company_state, company_website, company_zip FROM companies WHERE company_id = 1"); $row = mysqli_fetch_assoc($sql); $company_name = escapeSql($row['company_name']); $company_country = escapeSql($row['company_country']); @@ -370,7 +377,8 @@ if (isset($_POST['add_payment_stripe'])) { $config_invoice_from_email = escapeSql($config_invoice_from_email); // Get Client Payment Details - $sql = mysqli_query($mysqli, "SELECT * FROM client_saved_payment_methods LEFT JOIN payment_providers ON saved_payment_provider_id = payment_provider_id LEFT JOIN client_payment_provider ON saved_payment_client_id = client_id WHERE saved_payment_id = $saved_payment_id LIMIT 1"); + $sql = mysqli_query($mysqli, "SELECT payment_provider_account, payment_provider_client, payment_provider_private_key, + payment_provider_public_key, saved_payment_description, saved_payment_provider_method FROM client_saved_payment_methods LEFT JOIN payment_providers ON saved_payment_provider_id = payment_provider_id LEFT JOIN client_payment_provider ON saved_payment_client_id = client_id WHERE saved_payment_id = $saved_payment_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $public_key = escapeSql($row['payment_provider_public_key']); @@ -651,7 +659,7 @@ if (isset($_GET['delete_payment'])) { $payment_id = intval($_GET['delete_payment']); // payments has no client column - the client comes from the invoice the payment sits on - $sql = mysqli_query($mysqli,"SELECT * FROM payments + $sql = mysqli_query($mysqli,"SELECT invoice_client_id, invoice_number, invoice_prefix, payment_invoice_id FROM payments LEFT JOIN invoices ON payment_invoice_id = invoice_id WHERE payment_id = $payment_id LIMIT 1" diff --git a/agent/post/project.php b/agent/post/project.php index d55843961..66c7beec3 100644 --- a/agent/post/project.php +++ b/agent/post/project.php @@ -74,7 +74,7 @@ if (isset($_POST['add_project'])) { // Task Templates for Ticket template and add the to the ticket $sql_task_templates = mysqli_query($mysqli, - "SELECT * FROM task_templates WHERE task_template_ticket_template_id = $ticket_template_id"); + "SELECT task_template_id, task_template_name, task_template_order FROM task_templates WHERE task_template_ticket_template_id = $ticket_template_id"); $task_template_count = mysqli_num_rows($sql_task_templates); while ($row = mysqli_fetch_assoc($sql_task_templates)) { diff --git a/agent/post/quote.php b/agent/post/quote.php index ef0750221..b299160ea 100644 --- a/agent/post/quote.php +++ b/agent/post/quote.php @@ -79,7 +79,8 @@ if (isset($_POST['add_quote_copy'])) { $quote_number = mysqli_insert_id($mysqli); - $sql = mysqli_query($mysqli,"SELECT * FROM quotes WHERE quote_id = $quote_id"); + $sql = mysqli_query($mysqli,"SELECT quote_amount, quote_category_id, quote_currency_code, quote_discount_amount, quote_note, + quote_number, quote_prefix, quote_scope FROM quotes WHERE quote_id = $quote_id"); $row = mysqli_fetch_assoc($sql); $original_quote_prefix = escapeSql($row['quote_prefix']); $original_quote_number = escapeSql($row['quote_number']); @@ -135,7 +136,8 @@ if (isset($_POST['add_quote_to_invoice'])) { $quote_id = intval($_POST['quote_id']); $date = escapeSql($_POST['date']); - $sql = mysqli_query($mysqli,"SELECT * FROM clients, quotes WHERE client_id = quote_client_id AND quote_id = $quote_id"); + $sql = mysqli_query($mysqli,"SELECT client_net_terms, quote_amount, quote_category_id, quote_client_id, quote_currency_code, + quote_discount_amount, quote_note, quote_number, quote_prefix, quote_scope FROM clients, quotes WHERE client_id = quote_client_id AND quote_id = $quote_id"); $row = mysqli_fetch_assoc($sql); $client_net_terms = intval($row['client_net_terms']); $quote_prefix = escapeSql($row['quote_prefix']); @@ -241,7 +243,7 @@ if (isset($_POST['add_quote_item'])) { $subtotal = $price * $qty; if ($tax_id > 0) { - $sql = mysqli_query($mysqli,"SELECT * FROM taxes WHERE tax_id = $tax_id"); + $sql = mysqli_query($mysqli,"SELECT tax_percent FROM taxes WHERE tax_id = $tax_id"); $row = mysqli_fetch_assoc($sql); $tax_percent = floatval($row['tax_percent']); $tax_amount = $subtotal * $tax_percent / 100; @@ -254,7 +256,7 @@ if (isset($_POST['add_quote_item'])) { mysqli_query($mysqli,"INSERT INTO quote_items SET item_name = '$name', item_description = '$description', item_quantity = $qty, item_price = $price, item_subtotal = $subtotal, item_tax = $tax_amount, item_total = $total, item_tax_id = $tax_id, item_order = $item_order, item_quote_id = $quote_id"); // Get Quote Details - $sql = mysqli_query($mysqli,"SELECT * FROM quotes WHERE quote_id = $quote_id"); + $sql = mysqli_query($mysqli,"SELECT quote_client_id, quote_discount_amount, quote_number, quote_prefix FROM quotes WHERE quote_id = $quote_id"); $row = mysqli_fetch_assoc($sql); $quote_prefix = escapeSql($row['quote_prefix']); $quote_number = escapeSql($row['quote_number']); @@ -297,7 +299,7 @@ if (isset($_POST['edit_quote_item'])) { $subtotal = $price * $qty; if ($tax_id > 0) { - $sql = mysqli_query($mysqli,"SELECT * FROM taxes WHERE tax_id = $tax_id"); + $sql = mysqli_query($mysqli,"SELECT tax_percent FROM taxes WHERE tax_id = $tax_id"); $row = mysqli_fetch_assoc($sql); $tax_percent = floatval($row['tax_percent']); $tax_amount = $subtotal * $tax_percent / 100; @@ -313,7 +315,7 @@ if (isset($_POST['edit_quote_item'])) { $quote_id = intval($row['item_quote_id']); //Get Discount Amount - $sql = mysqli_query($mysqli,"SELECT * FROM quotes WHERE quote_id = $quote_id"); + $sql = mysqli_query($mysqli,"SELECT quote_client_id, quote_discount_amount, quote_number, quote_prefix FROM quotes WHERE quote_id = $quote_id"); $row = mysqli_fetch_assoc($sql); $quote_prefix = escapeSql($row['quote_prefix']); $quote_number = intval($row['quote_number']); @@ -349,7 +351,7 @@ if (isset($_POST['quote_note'])) { $note = escapeSql($_POST['note']); // Get Quote Details - $sql = mysqli_query($mysqli,"SELECT * FROM quotes WHERE quote_id = $quote_id"); + $sql = mysqli_query($mysqli,"SELECT quote_client_id, quote_number, quote_prefix FROM quotes WHERE quote_id = $quote_id"); $row = mysqli_fetch_assoc($sql); $quote_prefix = escapeSql($row['quote_prefix']); $quote_number = escapeSql($row['quote_number']); @@ -378,7 +380,7 @@ if (isset($_POST['edit_quote'])) { $quote_id = intval($_POST['quote_id']); // Get Quote Details for logging - $sql = mysqli_query($mysqli,"SELECT * FROM quotes WHERE quote_id = $quote_id"); + $sql = mysqli_query($mysqli,"SELECT quote_client_id, quote_number, quote_prefix FROM quotes WHERE quote_id = $quote_id"); $row = mysqli_fetch_assoc($sql); $quote_prefix = escapeSql($row['quote_prefix']); $quote_number = escapeSql($row['quote_number']); @@ -414,7 +416,7 @@ if (isset($_GET['delete_quote'])) { $quote_id = intval($_GET['delete_quote']); // Get Quote Details for logging - $sql = mysqli_query($mysqli,"SELECT * FROM quotes WHERE quote_id = $quote_id"); + $sql = mysqli_query($mysqli,"SELECT quote_client_id, quote_number, quote_prefix FROM quotes WHERE quote_id = $quote_id"); $row = mysqli_fetch_assoc($sql); $quote_prefix = escapeSql($row['quote_prefix']); $quote_number = escapeSql($row['quote_number']); @@ -432,7 +434,7 @@ if (isset($_GET['delete_quote'])) { } //Delete History Associated with the Quote - $sql = mysqli_query($mysqli,"SELECT * FROM history WHERE history_quote_id = $quote_id"); + $sql = mysqli_query($mysqli,"SELECT history_id FROM history WHERE history_quote_id = $quote_id"); while($row = mysqli_fetch_assoc($sql)) {; $history_id = intval($row['history_id']); mysqli_query($mysqli,"DELETE FROM history WHERE history_id = $history_id"); @@ -459,7 +461,7 @@ if (isset($_GET['delete_quote_item'])) { $item_id = intval($_GET['delete_quote_item']); - $sql = mysqli_query($mysqli,"SELECT * FROM quote_items WHERE item_id = $item_id"); + $sql = mysqli_query($mysqli,"SELECT item_name, item_quote_id, item_subtotal, item_tax, item_total FROM quote_items WHERE item_id = $item_id"); $row = mysqli_fetch_assoc($sql); $item_name = escapeSql($row['item_name']); $quote_id = intval($row['item_quote_id']); @@ -467,7 +469,7 @@ if (isset($_GET['delete_quote_item'])) { $item_tax = floatval($row['item_tax']); $item_total = floatval($row['item_total']); - $sql = mysqli_query($mysqli,"SELECT * FROM quotes WHERE quote_id = $quote_id"); + $sql = mysqli_query($mysqli,"SELECT quote_amount, quote_client_id, quote_number, quote_prefix FROM quotes WHERE quote_id = $quote_id"); $row = mysqli_fetch_assoc($sql); $quote_prefix = escapeSql($row['quote_prefix']); $quote_number = escapeSql($row['quote_number']); @@ -497,7 +499,7 @@ if (isset($_GET['mark_quote_sent'])) { $quote_id = intval($_GET['mark_quote_sent']); - $sql = mysqli_query($mysqli,"SELECT * FROM quotes WHERE quote_id = $quote_id"); + $sql = mysqli_query($mysqli,"SELECT quote_client_id, quote_number, quote_prefix FROM quotes WHERE quote_id = $quote_id"); $row = mysqli_fetch_assoc($sql); $quote_prefix = escapeSql($row['quote_prefix']); $quote_number = escapeSql($row['quote_number']); @@ -525,7 +527,7 @@ if (isset($_GET['accept_quote'])) { $quote_id = intval($_GET['accept_quote']); - $sql = mysqli_query($mysqli,"SELECT * FROM quotes WHERE quote_id = $quote_id"); + $sql = mysqli_query($mysqli,"SELECT quote_client_id, quote_number, quote_prefix FROM quotes WHERE quote_id = $quote_id"); $row = mysqli_fetch_assoc($sql); $quote_prefix = escapeSql($row['quote_prefix']); $quote_number = escapeSql($row['quote_number']); @@ -555,7 +557,7 @@ if (isset($_GET['decline_quote'])) { $quote_id = intval($_GET['decline_quote']); - $sql = mysqli_query($mysqli,"SELECT * FROM quotes WHERE quote_id = $quote_id"); + $sql = mysqli_query($mysqli,"SELECT quote_client_id, quote_number, quote_prefix FROM quotes WHERE quote_id = $quote_id"); $row = mysqli_fetch_assoc($sql); $quote_prefix = escapeSql($row['quote_prefix']); $quote_number = escapeSql($row['quote_number']); @@ -585,7 +587,9 @@ if (isset($_GET['email_quote'])) { $quote_id = intval($_GET['email_quote']); - $sql = mysqli_query($mysqli,"SELECT * FROM quotes + $sql = mysqli_query($mysqli,"SELECT client_id, client_name, contact_email, contact_name, quote_amount, quote_currency_code, + quote_date, quote_expire, quote_number, quote_prefix, quote_scope, quote_status, + quote_url_key FROM quotes LEFT JOIN clients ON quote_client_id = client_id LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1 WHERE quote_id = $quote_id" @@ -608,7 +612,8 @@ if (isset($_GET['email_quote'])) { enforceClientAccess(); - $sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1"); + $sql = mysqli_query($mysqli,"SELECT company_address, company_city, company_country, company_email, company_logo, company_name, + company_phone, company_phone_country_code, company_state, company_website, company_zip FROM companies WHERE company_id = 1"); $row = mysqli_fetch_assoc($sql); $company_name = escapeSql($row['company_name']); @@ -667,7 +672,7 @@ if (isset($_GET['mark_quote_invoiced'])) { $quote_id = intval($_GET['mark_quote_invoiced']); - $sql = mysqli_query($mysqli,"SELECT * FROM quotes WHERE quote_id = $quote_id"); + $sql = mysqli_query($mysqli,"SELECT quote_client_id, quote_number, quote_prefix FROM quotes WHERE quote_id = $quote_id"); $row = mysqli_fetch_assoc($sql); $quote_prefix = escapeSql($row['quote_prefix']); $quote_number = escapeSql($row['quote_number']); @@ -771,7 +776,12 @@ if (isset($_GET['export_quote_pdf'])) { $sql = mysqli_query( $mysqli, - "SELECT * FROM quotes + "SELECT client_currency_code, client_id, client_name, client_net_terms, client_website, + contact_email, contact_extension, contact_mobile, contact_mobile_country_code, + contact_phone, contact_phone_country_code, location_address, location_city, + location_country, location_state, location_zip, quote_amount, quote_category_id, + quote_created_at, quote_currency_code, quote_date, quote_discount_amount, quote_expire, + quote_id, quote_note, quote_number, quote_prefix, quote_scope, quote_status, quote_url_key FROM quotes LEFT JOIN clients ON quote_client_id = client_id LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1 LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1 @@ -817,7 +827,9 @@ if (isset($_GET['export_quote_pdf'])) { enforceClientAccess(); - $sql = mysqli_query($mysqli, "SELECT * FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1"); + $sql = mysqli_query($mysqli, "SELECT company_address, company_city, company_country, company_email, settings.company_id, + company_logo, company_name, company_phone, company_phone_country_code, company_state, + company_website, company_zip FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1"); $row = mysqli_fetch_assoc($sql); $company_id = intval($row['company_id']); diff --git a/agent/post/recurring_invoice.php b/agent/post/recurring_invoice.php index 0f9b182fe..e67b1aad5 100644 --- a/agent/post/recurring_invoice.php +++ b/agent/post/recurring_invoice.php @@ -15,7 +15,8 @@ if (isset($_POST['add_invoice_recurring'])) { $invoice_id = intval($_POST['invoice_id']); $recurring_invoice_frequency = validateRecurringFrequency($_POST['frequency']); - $sql = mysqli_query($mysqli,"SELECT * FROM invoices WHERE invoice_id = $invoice_id"); + $sql = mysqli_query($mysqli,"SELECT invoice_amount, invoice_category_id, invoice_client_id, invoice_currency_code, + invoice_date, invoice_note, invoice_number, invoice_prefix, invoice_scope FROM invoices WHERE invoice_id = $invoice_id"); $row = mysqli_fetch_assoc($sql); $invoice_prefix = escapeSql($row['invoice_prefix']); $invoice_number = intval($row['invoice_number']); @@ -182,7 +183,7 @@ if (isset($_GET['delete_recurring_invoice'])) { } //Delete History Associated with the Invoice - $sql = mysqli_query($mysqli,"SELECT * FROM history WHERE history_recurring_invoice_id = $recurring_invoice_id"); + $sql = mysqli_query($mysqli,"SELECT history_id FROM history WHERE history_recurring_invoice_id = $recurring_invoice_id"); while($row = mysqli_fetch_assoc($sql)) { $history_id = intval($row['history_id']); mysqli_query($mysqli,"DELETE FROM history WHERE history_id = $history_id"); @@ -217,7 +218,7 @@ if (isset($_POST['add_recurring_invoice_item'])) { $subtotal = $price * $qty; if ($tax_id > 0) { - $sql = mysqli_query($mysqli,"SELECT * FROM taxes WHERE tax_id = $tax_id"); + $sql = mysqli_query($mysqli,"SELECT tax_percent FROM taxes WHERE tax_id = $tax_id"); $row = mysqli_fetch_assoc($sql); $tax_percent = floatval($row['tax_percent']); $tax_amount = $subtotal * $tax_percent / 100; @@ -230,7 +231,8 @@ if (isset($_POST['add_recurring_invoice_item'])) { mysqli_query($mysqli,"INSERT INTO recurring_invoice_items SET item_name = '$name', item_description = '$description', item_quantity = $qty, item_price = $price, item_subtotal = $subtotal, item_tax = $tax_amount, item_total = $total, item_tax_id = $tax_id, item_order = $item_order, item_recurring_invoice_id = $recurring_invoice_id"); - $sql = mysqli_query($mysqli,"SELECT * FROM recurring_invoices WHERE recurring_invoice_id = $recurring_invoice_id"); + $sql = mysqli_query($mysqli,"SELECT recurring_invoice_client_id, recurring_invoice_discount_amount, recurring_invoice_number, + recurring_invoice_prefix FROM recurring_invoices WHERE recurring_invoice_id = $recurring_invoice_id"); $row = mysqli_fetch_assoc($sql); $recurring_invoice_discount = floatval($row['recurring_invoice_discount_amount']); $recurring_invoice_prefix = escapeSql($row['recurring_invoice_prefix']); @@ -273,7 +275,7 @@ if (isset($_POST['edit_recurring_invoice_item'])) { $subtotal = $price * $qty; if ($tax_id > 0) { - $sql = mysqli_query($mysqli,"SELECT * FROM taxes WHERE tax_id = $tax_id"); + $sql = mysqli_query($mysqli,"SELECT tax_percent FROM taxes WHERE tax_id = $tax_id"); $row = mysqli_fetch_assoc($sql); $tax_percent = floatval($row['tax_percent']); $tax_amount = $subtotal * $tax_percent / 100; @@ -289,7 +291,8 @@ if (isset($_POST['edit_recurring_invoice_item'])) { $recurring_invoice_id = intval($row['item_recurring_invoice_id']); //Get Discount Amount - $sql = mysqli_query($mysqli,"SELECT * FROM recurring_invoices WHERE recurring_invoice_id = $recurring_invoice_id"); + $sql = mysqli_query($mysqli,"SELECT recurring_invoice_client_id, recurring_invoice_discount_amount, recurring_invoice_number, + recurring_invoice_prefix FROM recurring_invoices WHERE recurring_invoice_id = $recurring_invoice_id"); $row = mysqli_fetch_assoc($sql); $recurring_invoice_prefix = escapeSql($row['recurring_invoice_prefix']); $recurring_invoice_number = intval($row['recurring_invoice_number']); @@ -352,7 +355,7 @@ if (isset($_GET['delete_recurring_invoice_item'])) { $item_id = intval($_GET['delete_recurring_invoice_item']); - $sql = mysqli_query($mysqli,"SELECT * FROM recurring_invoice_items WHERE item_id = $item_id"); + $sql = mysqli_query($mysqli,"SELECT item_name, item_recurring_invoice_id, item_subtotal, item_tax, item_total FROM recurring_invoice_items WHERE item_id = $item_id"); $row = mysqli_fetch_assoc($sql); $recurring_invoice_id = intval($row['item_recurring_invoice_id']); $item_name = escapeSql($row['item_name']); @@ -360,7 +363,8 @@ if (isset($_GET['delete_recurring_invoice_item'])) { $item_tax = floatval($row['item_tax']); $item_total = floatval($row['item_total']); - $sql = mysqli_query($mysqli,"SELECT * FROM recurring_invoices WHERE recurring_invoice_id = $recurring_invoice_id"); + $sql = mysqli_query($mysqli,"SELECT recurring_invoice_amount, recurring_invoice_client_id, recurring_invoice_number, + recurring_invoice_prefix FROM recurring_invoices WHERE recurring_invoice_id = $recurring_invoice_id"); $row = mysqli_fetch_assoc($sql); $recurring_invoice_prefix = escapeSql($row['recurring_invoice_prefix']); $recurring_invoice_number = intval($row['recurring_invoice_number']); @@ -390,7 +394,11 @@ if (isset($_GET['force_recurring'])) { $recurring_invoice_id = intval($_GET['force_recurring']); - $sql_recurring_invoices = mysqli_query($mysqli,"SELECT * FROM recurring_invoices, clients WHERE client_id = recurring_invoice_client_id AND recurring_invoice_id = $recurring_invoice_id"); + $sql_recurring_invoices = mysqli_query($mysqli,"SELECT client_net_terms, recurring_invoice_amount, recurring_invoice_category_id, + recurring_invoice_client_id, recurring_invoice_currency_code, + recurring_invoice_discount_amount, recurring_invoice_frequency, recurring_invoice_id, + recurring_invoice_last_sent, recurring_invoice_next_date, recurring_invoice_note, + recurring_invoice_scope, recurring_invoice_status FROM recurring_invoices, clients WHERE client_id = recurring_invoice_client_id AND recurring_invoice_id = $recurring_invoice_id"); $row = mysqli_fetch_assoc($sql_recurring_invoices); $recurring_invoice_id = intval($row['recurring_invoice_id']); @@ -442,7 +450,7 @@ if (isset($_GET['force_recurring'])) { //Recalculate Item Tax since Tax percents can change. if ($tax_id > 0) { - $sql = mysqli_query($mysqli,"SELECT * FROM taxes WHERE tax_id = $tax_id"); + $sql = mysqli_query($mysqli,"SELECT tax_percent FROM taxes WHERE tax_id = $tax_id"); $row = mysqli_fetch_assoc($sql); $tax_percent = floatval($row['tax_percent']); $item_tax_amount = $item_subtotal * $tax_percent / 100; @@ -493,7 +501,7 @@ if (isset($_GET['force_recurring'])) { $contact_extension = intval($row['contact_extension']); $contact_mobile = escapeSql(formatPhoneNumber($row['contact_mobile'], $row['contact_mobile_country_code'])); - $sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1"); + $sql = mysqli_query($mysqli,"SELECT company_email, company_name, company_phone, company_phone_country_code, company_website FROM companies WHERE company_id = 1"); $row = mysqli_fetch_assoc($sql); $company_name = escapeSql($row['company_name']); $company_phone = escapeSql(formatPhoneNumber($row['company_phone'], $row['company_phone_country_code'])); @@ -559,7 +567,8 @@ if (isset($_POST['set_recurring_payment'])) { $saved_payment_id = intval($_POST['saved_payment_id']); // Get Recurring Invoice Info for logging and alerting - $sql = mysqli_query($mysqli, "SELECT * FROM recurring_invoices WHERE recurring_invoice_id = $recurring_invoice_id"); + $sql = mysqli_query($mysqli, "SELECT recurring_invoice_amount, recurring_invoice_client_id, recurring_invoice_currency_code, + recurring_invoice_number, recurring_invoice_prefix FROM recurring_invoices WHERE recurring_invoice_id = $recurring_invoice_id"); $row = mysqli_fetch_assoc($sql); $client_id = intval($row['recurring_invoice_client_id']); $recurring_invoice_prefix = escapeSql($row['recurring_invoice_prefix']); @@ -573,7 +582,8 @@ if (isset($_POST['set_recurring_payment'])) { // Get Payment provider and method $sql = mysqli_query($mysqli, " - SELECT * FROM payment_providers + SELECT payment_provider_account, payment_provider_id, payment_provider_name, + saved_payment_description FROM payment_providers LEFT JOIN client_saved_payment_methods ON saved_payment_provider_id = payment_provider_id WHERE saved_payment_id = $saved_payment_id "); @@ -703,7 +713,7 @@ if (isset($_GET['recurring_invoice_email_notify'])) { $recurring_invoice_email_notify = intval($_GET['recurring_invoice_email_notify']); $recurring_invoice_id = intval($_GET['recurring_invoice_id']); - $sql = mysqli_query($mysqli,"SELECT * FROM recurring_invoices WHERE recurring_invoice_id = $recurring_invoice_id"); + $sql = mysqli_query($mysqli,"SELECT recurring_invoice_client_id, recurring_invoice_number, recurring_invoice_prefix FROM recurring_invoices WHERE recurring_invoice_id = $recurring_invoice_id"); $row = mysqli_fetch_assoc($sql); $recurring_invoice_prefix = escapeSql($row['recurring_invoice_prefix']); $recurring_invoice_number = intval($row['recurring_invoice_number']); diff --git a/agent/post/recurring_ticket.php b/agent/post/recurring_ticket.php index b65081ea1..a77e90d11 100644 --- a/agent/post/recurring_ticket.php +++ b/agent/post/recurring_ticket.php @@ -100,7 +100,10 @@ if (isset($_POST['bulk_force_recurring_tickets'])) { foreach ($_POST['recurring_ticket_ids'] as $recurring_ticket_id) { $recurring_ticket_id = intval($recurring_ticket_id); - $sql = mysqli_query($mysqli, "SELECT * FROM recurring_tickets WHERE recurring_ticket_id = $recurring_ticket_id"); + $sql = mysqli_query($mysqli, "SELECT recurring_ticket_asset_id, recurring_ticket_assigned_to, recurring_ticket_billable, + recurring_ticket_category, recurring_ticket_client_id, recurring_ticket_contact_id, + recurring_ticket_created_by, recurring_ticket_details, recurring_ticket_frequency, + recurring_ticket_next_run, recurring_ticket_priority, recurring_ticket_subject FROM recurring_tickets WHERE recurring_ticket_id = $recurring_ticket_id"); if (mysqli_num_rows($sql) > 0) { $row = mysqli_fetch_assoc($sql); @@ -244,7 +247,10 @@ if (isset($_GET['force_recurring_ticket'])) { $recurring_ticket_id = intval($_GET['force_recurring_ticket']); - $sql = mysqli_query($mysqli, "SELECT * FROM recurring_tickets WHERE recurring_ticket_id = $recurring_ticket_id"); + $sql = mysqli_query($mysqli, "SELECT recurring_ticket_asset_id, recurring_ticket_assigned_to, recurring_ticket_billable, + recurring_ticket_category, recurring_ticket_client_id, recurring_ticket_contact_id, + recurring_ticket_created_by, recurring_ticket_details, recurring_ticket_frequency, + recurring_ticket_next_run, recurring_ticket_priority, recurring_ticket_subject FROM recurring_tickets WHERE recurring_ticket_id = $recurring_ticket_id"); if (mysqli_num_rows($sql) > 0) { $row = mysqli_fetch_assoc($sql); @@ -389,7 +395,7 @@ if (isset($_GET['delete_recurring_ticket'])) { $recurring_ticket_id = intval($_GET['delete_recurring_ticket']); // Get Scheduled Ticket Subject Ticket Prefix, Number and Client ID for logging and alert message - $sql = mysqli_query($mysqli, "SELECT * FROM recurring_tickets WHERE recurring_ticket_id = $recurring_ticket_id"); + $sql = mysqli_query($mysqli, "SELECT recurring_ticket_client_id, recurring_ticket_frequency, recurring_ticket_subject FROM recurring_tickets WHERE recurring_ticket_id = $recurring_ticket_id"); $row = mysqli_fetch_assoc($sql); $subject = escapeSql($row['recurring_ticket_subject']); $frequency = escapeSql($row['recurring_ticket_frequency']); @@ -424,7 +430,7 @@ if (isset($_POST['bulk_delete_recurring_tickets'])) { $recurring_ticket_id = intval($recurring_ticket_id); // Get Scheduled Ticket Subject Ticket Prefix, Number and Client ID for logging and alert message - $sql = mysqli_query($mysqli, "SELECT * FROM recurring_tickets WHERE recurring_ticket_id = $recurring_ticket_id"); + $sql = mysqli_query($mysqli, "SELECT recurring_ticket_client_id, recurring_ticket_frequency, recurring_ticket_subject FROM recurring_tickets WHERE recurring_ticket_id = $recurring_ticket_id"); $row = mysqli_fetch_assoc($sql); $subject = escapeSql($row['recurring_ticket_subject']); $frequency = escapeSql($row['recurring_ticket_frequency']); diff --git a/agent/post/software.php b/agent/post/software.php index f3d952527..cf75fcda3 100644 --- a/agent/post/software.php +++ b/agent/post/software.php @@ -19,7 +19,8 @@ if (isset($_POST['add_software_from_template'])) { enforceClientAccess(); // GET Software Template Info - $sql_software_templates = mysqli_query($mysqli,"SELECT * FROM software_templates WHERE software_template_id = $software_template_id"); + $sql_software_templates = mysqli_query($mysqli,"SELECT software_template_description, software_template_license_type, software_template_name, + software_template_notes, software_template_type, software_template_version FROM software_templates WHERE software_template_id = $software_template_id"); $row = mysqli_fetch_assoc($sql_software_templates); $name = escapeSql($row['software_template_name']); $version = escapeSql($row['software_template_version']); diff --git a/agent/post/task.php b/agent/post/task.php index 914839afa..cb49fac26 100644 --- a/agent/post/task.php +++ b/agent/post/task.php @@ -43,7 +43,7 @@ if (isset($_POST['edit_ticket_task'])) { $task_completion_estimate = intval($_POST['completion_estimate']); // Get Client ID - $sql = mysqli_query($mysqli, "SELECT * FROM tasks LEFT JOIN tickets ON ticket_id = task_ticket_id WHERE task_id = $task_id"); + $sql = mysqli_query($mysqli, "SELECT ticket_client_id FROM tasks LEFT JOIN tickets ON ticket_id = task_ticket_id WHERE task_id = $task_id"); $row = mysqli_fetch_assoc($sql); $client_id = intval($row['ticket_client_id']); enforceClientAccess(); @@ -88,7 +88,7 @@ if (isset($_GET['delete_task'])) { $task_id = intval($_GET['delete_task']); // Get Client ID, task name from tasks and tickets using the task_id - $sql = mysqli_query($mysqli, "SELECT * FROM tasks LEFT JOIN tickets ON ticket_id = task_ticket_id WHERE task_id = $task_id"); + $sql = mysqli_query($mysqli, "SELECT task_name, ticket_client_id FROM tasks LEFT JOIN tickets ON ticket_id = task_ticket_id WHERE task_id = $task_id"); $row = mysqli_fetch_assoc($sql); $client_id = intval($row['ticket_client_id']); enforceClientAccess(); @@ -113,7 +113,7 @@ if (isset($_GET['complete_task'])) { $task_id = intval($_GET['complete_task']); // Get Client ID - $sql = mysqli_query($mysqli, "SELECT * FROM tasks LEFT JOIN tickets ON ticket_id = task_ticket_id WHERE task_id = $task_id"); + $sql = mysqli_query($mysqli, "SELECT task_completion_estimate, task_name, ticket_client_id, ticket_id FROM tasks LEFT JOIN tickets ON ticket_id = task_ticket_id WHERE task_id = $task_id"); $row = mysqli_fetch_assoc($sql); $client_id = intval($row['ticket_client_id']); enforceClientAccess(); @@ -148,7 +148,7 @@ if (isset($_GET['undo_complete_task'])) { $task_id = intval($_GET['undo_complete_task']); // Get Client ID - $sql = mysqli_query($mysqli, "SELECT * FROM tasks LEFT JOIN tickets ON ticket_id = task_ticket_id WHERE task_id = $task_id"); + $sql = mysqli_query($mysqli, "SELECT task_name, ticket_client_id, ticket_id FROM tasks LEFT JOIN tickets ON ticket_id = task_ticket_id WHERE task_id = $task_id"); $row = mysqli_fetch_assoc($sql); $client_id = intval($row['ticket_client_id']); enforceClientAccess(); @@ -192,7 +192,8 @@ if (isset($_POST['add_ticket_task_approver'])) { // Task/Ticket Info $tt_row = mysqli_fetch_assoc(mysqli_query($mysqli, " - SELECT * FROM tasks + SELECT task_name, task_ticket_id, ticket_client_id, ticket_contact_id, ticket_number, + ticket_prefix, ticket_status_name, ticket_subject, ticket_url_key FROM tasks LEFT JOIN tickets ON ticket_id = task_ticket_id LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id WHERE task_id = $task_id LIMIT 1 @@ -354,7 +355,8 @@ if (isset($_GET['approve_ticket_task'])) { $task_id = intval($_GET['approve_ticket_task']); $approval_id = intval($_GET['approval_id']); - $approval_row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM task_approvals LEFT JOIN tasks on task_id = approval_task_id WHERE approval_id = $approval_id AND approval_task_id = $task_id AND approval_scope = 'internal'")); + $approval_row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT approval_created_by, approval_required_user_id, approval_scope, approval_type, task_name, + task_ticket_id FROM task_approvals LEFT JOIN tasks on task_id = approval_task_id WHERE approval_id = $approval_id AND approval_task_id = $task_id AND approval_scope = 'internal'")); $task_name = escapeHtml($approval_row['task_name']); $scope = escapeHtml($approval_row['approval_scope']); diff --git a/agent/post/ticket.php b/agent/post/ticket.php index b1da09085..eb3bd0570 100644 --- a/agent/post/ticket.php +++ b/agent/post/ticket.php @@ -1171,7 +1171,7 @@ if (isset($_POST['bulk_edit_ticket_priority'])) { foreach ($_POST['ticket_ids'] as $ticket_id) { $ticket_id = intval($ticket_id); - $sql = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = $ticket_id"); + $sql = mysqli_query($mysqli, "SELECT ticket_client_id, ticket_number, ticket_prefix, ticket_priority, ticket_subject FROM tickets WHERE ticket_id = $ticket_id"); $row = mysqli_fetch_assoc($sql); $ticket_prefix = escapeSql($row['ticket_prefix']); @@ -1287,7 +1287,8 @@ if (isset($_POST['bulk_merge_tickets'])) { if ($ticket_id !== $merge_into_ticket_id) { - $sql = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = $ticket_id"); + $sql = mysqli_query($mysqli, "SELECT ticket_client_id, ticket_details, ticket_first_response_at, ticket_number, ticket_prefix, + ticket_priority, ticket_subject FROM tickets WHERE ticket_id = $ticket_id"); $row = mysqli_fetch_assoc($sql); $ticket_prefix = escapeSql($row['ticket_prefix']); @@ -1369,7 +1370,8 @@ if (isset($_POST['bulk_resolve_tickets'])) { // Count the Ticket Loop $ticket_count++; - $sql = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = $ticket_id"); + $sql = mysqli_query($mysqli, "SELECT ticket_client_id, ticket_first_response_at, ticket_number, ticket_prefix, ticket_priority, + ticket_subject, ticket_url_key FROM tickets WHERE ticket_id = $ticket_id"); $row = mysqli_fetch_assoc($sql); $ticket_prefix = escapeSql($row['ticket_prefix']); @@ -1509,7 +1511,8 @@ if (isset($_POST['bulk_ticket_reply'])) { foreach ($_POST['ticket_ids'] as $ticket_id) { $ticket_id = intval($ticket_id); - $sql = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = $ticket_id"); + $sql = mysqli_query($mysqli, "SELECT ticket_client_id, ticket_first_response_at, ticket_number, ticket_prefix, ticket_priority, + ticket_subject, ticket_url_key FROM tickets WHERE ticket_id = $ticket_id"); $row = mysqli_fetch_assoc($sql); $ticket_prefix = escapeSql($row['ticket_prefix']); @@ -1684,7 +1687,7 @@ if (isset($_POST['bulk_add_ticket_project'])) { foreach ($_POST['ticket_ids'] as $ticket_id) { $ticket_id = intval($ticket_id); - $sql = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = $ticket_id"); + $sql = mysqli_query($mysqli, "SELECT ticket_client_id, ticket_number, ticket_prefix, ticket_priority, ticket_subject FROM tickets WHERE ticket_id = $ticket_id"); $row = mysqli_fetch_assoc($sql); $ticket_prefix = escapeSql($row['ticket_prefix']); @@ -1737,7 +1740,7 @@ if (isset($_POST['bulk_add_asset_ticket'])) { // Check to see if adding a ticket by template if($ticket_template_id) { - $sql = mysqli_query($mysqli, "SELECT * FROM ticket_templates WHERE ticket_template_id = $ticket_template_id"); + $sql = mysqli_query($mysqli, "SELECT ticket_template_details, ticket_template_subject FROM ticket_templates WHERE ticket_template_id = $ticket_template_id"); $row = mysqli_fetch_assoc($sql); // Override Template Subject @@ -1756,7 +1759,7 @@ if (isset($_POST['bulk_add_asset_ticket'])) { foreach ($_POST['asset_ids'] as $asset_id) { $asset_id = intval($asset_id); - $sql = mysqli_query($mysqli, "SELECT * FROM assets WHERE asset_id = $asset_id"); + $sql = mysqli_query($mysqli, "SELECT asset_client_id, asset_name FROM assets WHERE asset_id = $asset_id"); $row = mysqli_fetch_assoc($sql); $asset_name = escapeSql($row['asset_name']); @@ -2301,7 +2304,7 @@ if (isset($_GET['resolve_ticket'])) { $ticket_id = intval($_GET['resolve_ticket']); - $sql = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = $ticket_id"); + $sql = mysqli_query($mysqli, "SELECT ticket_client_id, ticket_first_response_at, ticket_number, ticket_prefix FROM tickets WHERE ticket_id = $ticket_id"); $row = mysqli_fetch_assoc($sql); $ticket_prefix = escapeSql($row['ticket_prefix']); $ticket_number = intval($row['ticket_number']); @@ -2556,7 +2559,9 @@ if (isset($_POST['add_invoice_from_ticket'])) { $sql = mysqli_query( $mysqli, - "SELECT * FROM tickets + "SELECT asset_id, client_id, client_net_terms, contact_email, contact_id, contact_name, + location_name, ticket_category, ticket_closed_at, ticket_created_at, ticket_number, + ticket_prefix, ticket_subject, ticket_updated_at FROM tickets LEFT JOIN clients ON ticket_client_id = client_id LEFT JOIN contacts ON ticket_contact_id = contact_id LEFT JOIN assets ON ticket_asset_id = asset_id @@ -2626,7 +2631,7 @@ if (isset($_POST['add_invoice_from_ticket'])) { $subtotal = $price * $qty; if ($tax_id > 0) { - $sql = mysqli_query($mysqli, "SELECT * FROM taxes WHERE tax_id = $tax_id"); + $sql = mysqli_query($mysqli, "SELECT tax_percent FROM taxes WHERE tax_id = $tax_id"); $row = mysqli_fetch_assoc($sql); $tax_percent = floatval($row['tax_percent']); $tax_amount = $subtotal * $tax_percent / 100; @@ -2640,7 +2645,7 @@ if (isset($_POST['add_invoice_from_ticket'])) { //Update Invoice Balances - $sql = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_id = $invoice_id"); + $sql = mysqli_query($mysqli, "SELECT invoice_amount FROM invoices WHERE invoice_id = $invoice_id"); $row = mysqli_fetch_assoc($sql); $new_invoice_amount = floatval($row['invoice_amount']) + $total; @@ -2682,7 +2687,7 @@ if (isset($_POST['add_quote_from_ticket'])) { $subtotal = $price * $qty; $tax_amount = 0; if ($tax_id > 0) { - $sql = mysqli_query($mysqli, "SELECT * FROM taxes WHERE tax_id = $tax_id"); + $sql = mysqli_query($mysqli, "SELECT tax_percent FROM taxes WHERE tax_id = $tax_id"); $row = mysqli_fetch_assoc($sql); $tax_percent = floatval($row['tax_percent']); $tax_amount = $subtotal * $tax_percent / 100; @@ -3187,7 +3192,8 @@ if (isset($_GET['cancel_ticket_schedule'])) { //Send emails - $sql = mysqli_query($mysqli, "SELECT * FROM tickets + $sql = mysqli_query($mysqli, "SELECT client_name, contact_email, contact_name, ticket_client_id, ticket_details, ticket_number, + ticket_prefix, ticket_subject, user_email, user_name FROM tickets LEFT JOIN clients ON ticket_client_id = client_id LEFT JOIN contacts ON ticket_contact_id = contact_id LEFT JOIN locations on contact_location_id = location_id diff --git a/agent/post/transaction.php b/agent/post/transaction.php index 672094d5b..0cdd368c7 100644 --- a/agent/post/transaction.php +++ b/agent/post/transaction.php @@ -103,7 +103,7 @@ if (isset($_POST['export_transactions'])) { if ($account) { // Account details for the running balance and file name - $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM accounts WHERE account_id = $account LIMIT 1")); + $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT account_name, opening_balance FROM accounts WHERE account_id = $account LIMIT 1")); $account_name = $row['account_name']; $account_opening_balance = floatval($row['opening_balance']); diff --git a/agent/post/transfer.php b/agent/post/transfer.php index a67c6eb64..2b427bc60 100644 --- a/agent/post/transfer.php +++ b/agent/post/transfer.php @@ -78,7 +78,7 @@ if (isset($_GET['delete_transfer'])) { $transfer_id = intval($_GET['delete_transfer']); // Query the transfer ID to get the Payment and Expense IDs, so we can delete those as well - $row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT * FROM transfers WHERE transfer_id = $transfer_id")); + $row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT transfer_expense_id, transfer_revenue_id FROM transfers WHERE transfer_id = $transfer_id")); $expense_id = intval($row['transfer_expense_id']); $revenue_id = intval($row['transfer_revenue_id']); diff --git a/agent/post/trip.php b/agent/post/trip.php index 096a89938..86c6ec71a 100644 --- a/agent/post/trip.php +++ b/agent/post/trip.php @@ -65,7 +65,7 @@ if (isset($_GET['delete_trip'])) { $trip_id = intval($_GET['delete_trip']); // Get Trip Info and Client ID for logging - $row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT * FROM trips WHERE trip_id = $trip_id")); + $row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT trip_client_id, trip_destination, trip_source FROM trips WHERE trip_id = $trip_id")); $client_id = intval($row['trip_client_id']); $trip_source = escapeSql($row['trip_source']); $trip_destination = escapeSql($row['trip_destination']); diff --git a/agent/post/vendor.php b/agent/post/vendor.php index 6eadbf2b3..d263a7bb1 100644 --- a/agent/post/vendor.php +++ b/agent/post/vendor.php @@ -26,7 +26,10 @@ if (isset($_POST['add_vendor_from_template'])) { $vendor_template_id = intval($_POST['vendor_template_id']); //GET Vendor Info - $sql_vendor_templates = mysqli_query($mysqli,"SELECT * FROM vendor_templates WHERE vendor_template_id = $vendor_template_id"); + $sql_vendor_templates = mysqli_query($mysqli,"SELECT vendor_template_account_number, vendor_template_code, vendor_template_contact_name, + vendor_template_description, vendor_template_email, vendor_template_extension, + vendor_template_hours, vendor_template_name, vendor_template_notes, vendor_template_phone, + vendor_template_phone_country_code, vendor_template_sla, vendor_template_website FROM vendor_templates WHERE vendor_template_id = $vendor_template_id"); $row = mysqli_fetch_assoc($sql_vendor_templates); @@ -124,7 +127,7 @@ if (isset($_GET['archive_vendor'])) { $vendor_id = intval($_GET['archive_vendor']); //Get Vendor Name - $sql = mysqli_query($mysqli,"SELECT * FROM vendors WHERE vendor_id = $vendor_id"); + $sql = mysqli_query($mysqli,"SELECT vendor_client_id, vendor_name FROM vendors WHERE vendor_id = $vendor_id"); $row = mysqli_fetch_assoc($sql); $vendor_name = escapeSql($row['vendor_name']); $client_id = intval($row['vendor_client_id']); @@ -184,7 +187,7 @@ if (isset($_GET['delete_vendor'])) { $vendor_id = intval($_GET['delete_vendor']); //Get Vendor Name - $sql = mysqli_query($mysqli,"SELECT * FROM vendors WHERE vendor_id = $vendor_id"); + $sql = mysqli_query($mysqli,"SELECT vendor_client_id, vendor_name, vendor_template_id FROM vendors WHERE vendor_id = $vendor_id"); $row = mysqli_fetch_assoc($sql); $vendor_name = escapeSql($row['vendor_name']); $client_id = intval($row['vendor_client_id']); diff --git a/agent/project.php b/agent/project.php index 7a5d625c9..85e1b4531 100644 --- a/agent/project.php +++ b/agent/project.php @@ -26,7 +26,9 @@ if (isset($_GET['project_id'])) { $sql_project = mysqli_query( $mysqli, - "SELECT * FROM projects + "SELECT client_id, client_name, project_archived_at, project_completed_at, project_created_at, + project_description, project_due, project_id, project_name, project_number, project_prefix, + project_updated_at, user_id, user_name FROM projects LEFT JOIN clients ON project_client_id = client_id LEFT JOIN users ON project_manager = user_id WHERE project_id = $project_id diff --git a/agent/quote.php b/agent/quote.php index a5fa73a87..b9b8837de 100644 --- a/agent/quote.php +++ b/agent/quote.php @@ -16,7 +16,12 @@ if (isset($_GET['quote_id'])) { $sql = mysqli_query( $mysqli, - "SELECT * FROM quotes + "SELECT client_currency_code, client_id, client_name, client_net_terms, client_website, + contact_email, contact_extension, contact_mobile, contact_mobile_country_code, + contact_phone, contact_phone_country_code, location_address, location_city, + location_country, location_state, location_zip, quote_amount, quote_category_id, + quote_created_at, quote_currency_code, quote_date, quote_discount_amount, quote_expire, + quote_id, quote_note, quote_number, quote_prefix, quote_scope, quote_status, quote_url_key FROM quotes LEFT JOIN clients ON quote_client_id = client_id LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1 LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1 @@ -76,7 +81,9 @@ if (isset($_GET['quote_id'])) { $tab_title = $row['client_name']; $page_title = "{$row['quote_prefix']}{$row['quote_number']}"; - $sql = mysqli_query($mysqli, "SELECT * FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1"); + $sql = mysqli_query($mysqli, "SELECT company_address, company_city, company_country, company_email, settings.company_id, + company_logo, company_name, company_phone, company_phone_country_code, company_state, + company_website, company_zip FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1"); $row = mysqli_fetch_assoc($sql); $company_id = intval($row['company_id']); @@ -92,7 +99,7 @@ if (isset($_GET['quote_id'])) { $company_website = escapeHtml($row['company_website']); $company_logo = escapeHtml($row['company_logo']); - $sql_history = mysqli_query($mysqli, "SELECT * FROM history WHERE history_quote_id = $quote_id ORDER BY history_id DESC"); + $sql_history = mysqli_query($mysqli, "SELECT history_created_at, history_description, history_status FROM history WHERE history_quote_id = $quote_id ORDER BY history_id DESC"); //Set Badge color based off of quote status if ($quote_status == "Sent") { diff --git a/agent/recurring_invoice.php b/agent/recurring_invoice.php index 02028422a..a1fef0f17 100644 --- a/agent/recurring_invoice.php +++ b/agent/recurring_invoice.php @@ -15,7 +15,17 @@ if (isset($_GET['recurring_invoice_id'])) { $sql = mysqli_query( $mysqli, - "SELECT * FROM recurring_invoices + "SELECT client_currency_code, client_id, client_name, client_net_terms, client_website, + contact_email, contact_extension, contact_mobile, contact_mobile_country_code, + contact_phone, contact_phone_country_code, location_address, location_city, + location_country, location_state, location_zip, recurring_invoice_amount, + recurring_invoice_category_id, recurring_invoice_created_at, + recurring_invoice_currency_code, recurring_invoice_discount_amount, + recurring_invoice_email_notify, recurring_invoice_frequency, recurring_invoice_last_sent, + recurring_invoice_next_date, recurring_invoice_note, recurring_invoice_number, + recurring_invoice_prefix, recurring_invoice_scope, recurring_invoice_status, + recurring_payment_id, recurring_payment_method, recurring_payment_recurring_invoice_id, + recurring_payment_saved_payment_id FROM recurring_invoices LEFT JOIN clients ON recurring_invoice_client_id = client_id LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1 LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1 @@ -86,7 +96,9 @@ if (isset($_GET['recurring_invoice_id'])) { $tab_title = $row['client_name']; $page_title = "{$row['recurring_invoice_prefix']}{$row['recurring_invoice_number']}"; - $sql = mysqli_query($mysqli, "SELECT * FROM companies WHERE company_id = 1"); + $sql = mysqli_query($mysqli, "SELECT company_address, company_city, company_country, company_email, company_id, company_logo, + company_name, company_phone, company_phone_country_code, company_state, company_website, + company_zip FROM companies WHERE company_id = 1"); $row = mysqli_fetch_assoc($sql); $company_id = intval($row['company_id']); @@ -102,7 +114,7 @@ if (isset($_GET['recurring_invoice_id'])) { $company_website = escapeHtml($row['company_website']); $company_logo = escapeHtml($row['company_logo']); - $sql_history = mysqli_query($mysqli, "SELECT * FROM history WHERE history_recurring_invoice_id = $recurring_invoice_id ORDER BY history_id DESC"); + $sql_history = mysqli_query($mysqli, "SELECT history_created_at, history_description, history_status FROM history WHERE history_recurring_invoice_id = $recurring_invoice_id ORDER BY history_id DESC"); //Product autocomplete $products_sql = mysqli_query($mysqli, "SELECT product_name AS label, product_description AS description, product_price AS price, product_tax_id AS tax FROM products WHERE product_archived_at IS NULL"); @@ -150,7 +162,7 @@ if (isset($_GET['recurring_invoice_id'])) {
- 0) { ?>
diff --git a/agent/recurring_invoices.php b/agent/recurring_invoices.php index d68ed4415..9e89482c7 100644 --- a/agent/recurring_invoices.php +++ b/agent/recurring_invoices.php @@ -218,7 +218,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); - 0) { ?> diff --git a/agent/reports/expense_summary.php b/agent/reports/expense_summary.php index 698231712..0f4df0927 100644 --- a/agent/reports/expense_summary.php +++ b/agent/reports/expense_summary.php @@ -12,7 +12,7 @@ if (isset($_GET['year'])) { $sql_expense_years = mysqli_query($mysqli, "SELECT DISTINCT YEAR(expense_date) AS expense_year FROM expenses WHERE expense_category_id > 0 ORDER BY expense_year DESC"); -$sql_categories = mysqli_query($mysqli, "SELECT * FROM categories WHERE category_type = 'Expense' ORDER BY category_name ASC"); +$sql_categories = mysqli_query($mysqli, "SELECT category_id, category_name FROM categories WHERE category_type = 'Expense' ORDER BY category_name ASC"); // For chart Y-axis max $largest_expense_month = 0; diff --git a/agent/reports/income_summary.php b/agent/reports/income_summary.php index 0678c563e..642799f63 100644 --- a/agent/reports/income_summary.php +++ b/agent/reports/income_summary.php @@ -14,7 +14,7 @@ $sql_payment_years = mysqli_query($mysqli, "SELECT DISTINCT YEAR(payment_date) A UNION SELECT DISTINCT YEAR(revenue_date) AS payment_year FROM revenues ORDER BY payment_year DESC"); -$sql_categories = mysqli_query($mysqli, "SELECT * FROM categories WHERE category_type = 'Income' ORDER BY category_name ASC"); +$sql_categories = mysqli_query($mysqli, "SELECT category_id, category_name FROM categories WHERE category_type = 'Income' ORDER BY category_name ASC"); // Used for chart y-axis max calculation $largest_income_month = 0; diff --git a/agent/ticket.php b/agent/ticket.php index 41e21e73f..710b66e76 100644 --- a/agent/ticket.php +++ b/agent/ticket.php @@ -295,7 +295,7 @@ if (isset($_GET['ticket_id'])) { } // Get Watchers - $sql_ticket_watchers = mysqli_query($mysqli, "SELECT * FROM ticket_watchers WHERE watcher_ticket_id = $ticket_id ORDER BY watcher_email DESC"); + $sql_ticket_watchers = mysqli_query($mysqli, "SELECT watcher_email, watcher_id FROM ticket_watchers WHERE watcher_ticket_id = $ticket_id ORDER BY watcher_email DESC"); $watcher_count = mysqli_num_rows($sql_ticket_watchers); // Get Additional Assets @@ -306,7 +306,7 @@ if (isset($_GET['ticket_id'])) { ); // Get Tasks - $sql_tasks = mysqli_query($mysqli, "SELECT * FROM tasks WHERE task_ticket_id = $ticket_id ORDER BY task_order ASC, task_id ASC"); + $sql_tasks = mysqli_query($mysqli, "SELECT task_completed_at, task_completion_estimate, task_id, task_name FROM tasks WHERE task_ticket_id = $ticket_id ORDER BY task_order ASC, task_id ASC"); $task_count = mysqli_num_rows($sql_tasks); $completed_task_count = intval(mysqli_fetch_row(mysqli_query( diff --git a/agent/transactions.php b/agent/transactions.php index 8218257fe..f2f12f4bc 100644 --- a/agent/transactions.php +++ b/agent/transactions.php @@ -86,7 +86,7 @@ if ($sort == 'transaction_date') { if ($account_filter) { // Account details - opening balance feeds the running balance, currency feeds the summary - $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM accounts WHERE account_id = $account_filter LIMIT 1")); + $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT account_currency_code, opening_balance FROM accounts WHERE account_id = $account_filter LIMIT 1")); $account_currency_code = escapeHtml($row['account_currency_code']); $account_opening_balance = floatval($row['opening_balance']); diff --git a/agent/transfers.php b/agent/transfers.php index 6df181a35..409c1c88e 100644 --- a/agent/transfers.php +++ b/agent/transfers.php @@ -182,7 +182,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $expense_id = intval($row['transfer_expense_id']); $revenue_id = intval($row['transfer_revenue_id']); - $sql_from = mysqli_query($mysqli, "SELECT * FROM accounts WHERE account_id = $transfer_account_from"); + $sql_from = mysqli_query($mysqli, "SELECT account_archived_at, account_name FROM accounts WHERE account_id = $transfer_account_from"); $row = mysqli_fetch_assoc($sql_from); $account_name_from = escapeHtml($row['account_name']); $account_from_archived_at = escapeHtml($row['account_archived_at']); @@ -192,7 +192,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $account_from_archived_display = "Archived - "; } - $sql_to = mysqli_query($mysqli, "SELECT * FROM accounts WHERE account_id = $transfer_account_to"); + $sql_to = mysqli_query($mysqli, "SELECT account_archived_at, account_name FROM accounts WHERE account_id = $transfer_account_to"); $row = mysqli_fetch_assoc($sql_to); $account_name_to = escapeHtml($row['account_name']); $account_to_archived_at = escapeHtml($row['account_archived_at']); diff --git a/agent/user/user_activity.php b/agent/user/user_activity.php index 642646ab4..0a842e54e 100644 --- a/agent/user/user_activity.php +++ b/agent/user/user_activity.php @@ -2,12 +2,12 @@ require_once "includes/inc_all_user.php"; -$sql_recent_logins = mysqli_query($mysqli, "SELECT * FROM logs +$sql_recent_logins = mysqli_query($mysqli, "SELECT log_created_at, log_id, log_ip, log_user_agent FROM logs WHERE log_type = 'Login' OR log_type = 'Login 2FA' AND log_action = 'Success' AND log_user_id = $session_user_id ORDER BY log_id DESC LIMIT 3" ); -$sql_recent_logs = mysqli_query($mysqli, "SELECT * FROM logs +$sql_recent_logs = mysqli_query($mysqli, "SELECT log_action, log_created_at, log_description, log_id, log_type FROM logs WHERE log_user_id = $session_user_id AND log_type NOT LIKE 'Login' ORDER BY log_id DESC LIMIT 5" ); diff --git a/agent/user/user_security.php b/agent/user/user_security.php index 96193a74f..b2e89bcac 100644 --- a/agent/user/user_security.php +++ b/agent/user/user_security.php @@ -2,7 +2,7 @@ require_once "includes/inc_all_user.php"; // User remember me tokens -$sql_remember_tokens = mysqli_query($mysqli, "SELECT * FROM remember_tokens WHERE remember_token_user_id = $session_user_id"); +$sql_remember_tokens = mysqli_query($mysqli, "SELECT remember_token_created_at, remember_token_id FROM remember_tokens WHERE remember_token_user_id = $session_user_id"); $remember_token_count = mysqli_num_rows($sql_remember_tokens); ?> diff --git a/api/v1/assets/delete.php b/api/v1/assets/delete.php index 871e53c5f..e87e9caf0 100644 --- a/api/v1/assets/delete.php +++ b/api/v1/assets/delete.php @@ -12,7 +12,7 @@ $asset_id = intval($_POST['asset_id']); $delete_count = false; if (!empty($asset_id)) { - $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM assets WHERE asset_id = $asset_id AND asset_client_id = $client_id LIMIT 1")); + $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT asset_name FROM assets WHERE asset_id = $asset_id AND asset_client_id = $client_id LIMIT 1")); $asset_name = $row['asset_name']; $delete_sql = mysqli_query($mysqli, "DELETE FROM assets WHERE asset_id = $asset_id AND asset_client_id = $client_id LIMIT 1"); diff --git a/api/v1/contacts/create.php b/api/v1/contacts/create.php index 3079b7cc0..34b0a6b92 100644 --- a/api/v1/contacts/create.php +++ b/api/v1/contacts/create.php @@ -15,7 +15,7 @@ $insert_id = false; if (!empty($name) && !empty($email) && !empty($client_id)) { // Check contact with $email doesn't already exist - $email_duplication_sql = mysqli_query($mysqli, "SELECT * FROM contacts WHERE contact_email = '$email' AND contact_client_id = '$client_id'"); + $email_duplication_sql = mysqli_query($mysqli, "SELECT 1 FROM contacts WHERE contact_email = '$email' AND contact_client_id = '$client_id'"); if (mysqli_num_rows($email_duplication_sql) == 0) { diff --git a/api/v1/contacts/delete.php b/api/v1/contacts/delete.php index 8066fdd33..3332e2234 100644 --- a/api/v1/contacts/delete.php +++ b/api/v1/contacts/delete.php @@ -12,7 +12,7 @@ $contact_id = intval($_POST['contact_id']); $delete_count = false; if (!empty($contact_id)) { - $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM contacts WHERE contact_id = $contact_id AND contact_client_id = $client_id LIMIT 1")); + $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT contact_name FROM contacts WHERE contact_id = $contact_id AND contact_client_id = $client_id LIMIT 1")); $contact_name = $row['contact_name']; $delete_sql = mysqli_query($mysqli, "DELETE FROM contacts WHERE contact_id = $contact_id AND contact_client_id = $client_id LIMIT 1"); diff --git a/api/v1/documents/update.php b/api/v1/documents/update.php index 166a02128..8c845e8a4 100644 --- a/api/v1/documents/update.php +++ b/api/v1/documents/update.php @@ -14,7 +14,8 @@ if (!empty($document_id)) { // 1) Load the current document (scoped to this client) $sql_original_document = mysqli_query( $mysqli, - "SELECT * FROM documents + "SELECT document_content, document_created_at, document_created_by, document_description, + document_name, document_updated_at, document_updated_by FROM documents WHERE document_client_id = $client_id AND document_id = $document_id LIMIT 1" diff --git a/api/v1/tickets/resolve.php b/api/v1/tickets/resolve.php index 3790f0ec8..31be07310 100644 --- a/api/v1/tickets/resolve.php +++ b/api/v1/tickets/resolve.php @@ -15,7 +15,7 @@ $update_count = false; if (!empty($ticket_id)) { - $ticket_row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = '$ticket_id' AND ticket_resolved_at IS NULL AND ticket_client_id = $client_id LIMIT 1")); + $ticket_row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT ticket_first_response_at, ticket_id, ticket_number, ticket_prefix FROM tickets WHERE ticket_id = '$ticket_id' AND ticket_resolved_at IS NULL AND ticket_client_id = $client_id LIMIT 1")); // Grab what we need, not using the model $ticket_id = intval($ticket_row['ticket_id']); // Override so things fail if this is bad diff --git a/api/v1/validate_api_key.php b/api/v1/validate_api_key.php index 2404bc8c5..98084ae88 100644 --- a/api/v1/validate_api_key.php +++ b/api/v1/validate_api_key.php @@ -70,7 +70,7 @@ if (isset($_POST['api_key'])) { if (isset($api_key)) { $api_key = escapeSql($api_key); - $sql = mysqli_query($mysqli, "SELECT * FROM api_keys WHERE api_key_secret = '$api_key' AND api_key_expire > NOW() LIMIT 1"); + $sql = mysqli_query($mysqli, "SELECT api_key_decrypt_hash, api_key_name, api_key_user_id FROM api_keys WHERE api_key_secret = '$api_key' AND api_key_expire > NOW() LIMIT 1"); // Failed if (mysqli_num_rows($sql) !== 1) { diff --git a/client/includes/check_login.php b/client/includes/check_login.php index 25fb5af86..223ab841c 100644 --- a/client/includes/check_login.php +++ b/client/includes/check_login.php @@ -25,7 +25,7 @@ $session_contact_id = intval($_SESSION['contact_id']); $session_user_id = intval($_SESSION['user_id']); // Load user session vars -$sql = mysqli_query($mysqli, "SELECT * FROM users WHERE users.user_id = $session_user_id"); +$sql = mysqli_query($mysqli, "SELECT user_archived_at, user_avatar, user_status, user_type FROM users WHERE users.user_id = $session_user_id"); $row = mysqli_fetch_assoc($sql); @@ -56,7 +56,7 @@ if ($session_user_archived_at !== null) { } // Load company session vars -$sql = mysqli_query($mysqli, "SELECT * FROM companies WHERE company_id = 1"); +$sql = mysqli_query($mysqli, "SELECT company_country, company_currency, company_locale, company_logo, company_name FROM companies WHERE company_id = 1"); $row = mysqli_fetch_assoc($sql); $session_company_name = $row['company_name']; @@ -67,7 +67,8 @@ $currency_format = numfmt_create($session_company_locale, NumberFormatter::CURRE $session_company_logo = $row['company_logo']; // Load contact session vars -$contact_sql = mysqli_query($mysqli, "SELECT * FROM contacts WHERE contact_id = $session_contact_id AND contact_client_id = $session_client_id"); +$contact_sql = mysqli_query($mysqli, "SELECT contact_billing, contact_email, contact_name, contact_photo, contact_pin, contact_primary, + contact_technical, contact_title FROM contacts WHERE contact_id = $session_contact_id AND contact_client_id = $session_client_id"); $contact = mysqli_fetch_assoc($contact_sql); $session_contact_name = escapeSql($contact['contact_name']); @@ -88,7 +89,7 @@ if ($contact['contact_billing'] == 1) { } // Load client session vars -$client_sql = mysqli_query($mysqli, "SELECT * FROM clients WHERE client_id = $session_client_id"); +$client_sql = mysqli_query($mysqli, "SELECT client_name FROM clients WHERE client_id = $session_client_id"); $client = mysqli_fetch_assoc($client_sql); $session_client_name = $client['client_name']; diff --git a/client/login_microsoft.php b/client/login_microsoft.php index 2c603b608..5a4179b86 100644 --- a/client/login_microsoft.php +++ b/client/login_microsoft.php @@ -126,7 +126,7 @@ if (isset($_GET['code']) || isset($_GET['error'])) { $upn = mysqli_real_escape_string($mysqli, $msgraph_response["userPrincipalName"]); - $sql = mysqli_query($mysqli, "SELECT * FROM users + $sql = mysqli_query($mysqli, "SELECT contact_client_id, contact_id, user_auth_method, user_email, user_id FROM users LEFT JOIN contacts ON user_id = contact_user_id LEFT JOIN clients ON contact_client_id = client_id WHERE user_email = '$upn' diff --git a/client/login_reset.php b/client/login_reset.php index 584fd105a..18bdbac9a 100644 --- a/client/login_reset.php +++ b/client/login_reset.php @@ -109,7 +109,7 @@ if ($_SERVER['REQUEST_METHOD'] == "POST") { $client = intval($_POST['client']); // Query user - $sql = mysqli_query($mysqli, "SELECT * FROM users LEFT JOIN contacts ON user_id = contact_user_id WHERE user_email = '$email' AND user_password_reset_token = '$token' AND contact_client_id = $client AND user_auth_method = 'local' AND user_type = 2 AND user_status = 1 AND user_archived_at IS NULL LIMIT 1"); + $sql = mysqli_query($mysqli, "SELECT contact_id, contact_name, user_id, user_password_reset_token FROM users LEFT JOIN contacts ON user_id = contact_user_id WHERE user_email = '$email' AND user_password_reset_token = '$token' AND contact_client_id = $client AND user_auth_method = 'local' AND user_type = 2 AND user_status = 1 AND user_archived_at IS NULL LIMIT 1"); $user_row = mysqli_fetch_assoc($sql); $contact_id = intval($user_row['contact_id']); $user_id = intval($user_row['user_id']); @@ -207,7 +207,7 @@ if ($_SERVER['REQUEST_METHOD'] == "POST") { $email = escapeSql($_GET['email']); $client = intval($_GET['client']); - $sql = mysqli_query($mysqli, "SELECT * FROM users LEFT JOIN contacts ON user_id = contact_user_id WHERE user_email = '$email' AND user_password_reset_token = '$token' AND contact_client_id = $client LIMIT 1"); + $sql = mysqli_query($mysqli, "SELECT user_password_reset_token FROM users LEFT JOIN contacts ON user_id = contact_user_id WHERE user_email = '$email' AND user_password_reset_token = '$token' AND contact_client_id = $client LIMIT 1"); $user_row = mysqli_fetch_assoc($sql); // Sanity check diff --git a/client/post.php b/client/post.php index 3b333d7bd..3f03302a7 100644 --- a/client/post.php +++ b/client/post.php @@ -111,7 +111,7 @@ if (isset($_POST['add_ticket_comment'])) { // Get ticket details & Notify the assigned tech (if any) - $ticket_details = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM tickets LEFT JOIN clients ON ticket_client_id = client_id WHERE ticket_id = $ticket_id LIMIT 1")); + $ticket_details = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT client_name, ticket_assigned_to, ticket_number, ticket_subject FROM tickets LEFT JOIN clients ON ticket_client_id = client_id WHERE ticket_id = $ticket_id LIMIT 1")); $ticket_number = intval($ticket_details['ticket_number']); $ticket_assigned_to = intval($ticket_details['ticket_assigned_to']); @@ -166,7 +166,8 @@ if (isset($_GET['approve_ticket_task'])) { $approval_id = intval($_GET['approval_id']); $url_key = escapeSql($_GET['approval_url_key']); - $approval_row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM task_approvals LEFT JOIN tasks on task_id = approval_task_id WHERE approval_id = $approval_id AND approval_task_id = $task_id AND approval_url_key = '$url_key' AND approval_status = 'pending' AND approval_scope = 'client'")); + $approval_row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT approval_created_by, approval_required_user_id, approval_scope, approval_type, task_name, + task_ticket_id FROM task_approvals LEFT JOIN tasks on task_id = approval_task_id WHERE approval_id = $approval_id AND approval_task_id = $task_id AND approval_url_key = '$url_key' AND approval_status = 'pending' AND approval_scope = 'client'")); $task_name = escapeHtml($approval_row['task_name']); $scope = escapeHtml($approval_row['approval_scope']); @@ -236,7 +237,7 @@ if (isset($_GET['resolve_ticket'])) { $ticket_id = intval($_GET['resolve_ticket']); // Get ticket details for logging - $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = $ticket_id LIMIT 1")); + $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT ticket_number, ticket_prefix FROM tickets WHERE ticket_id = $ticket_id LIMIT 1")); $ticket_prefix = escapeSql($row['ticket_prefix']); $ticket_number = intval($row['ticket_number']); @@ -274,7 +275,7 @@ if (isset($_GET['reopen_ticket'])) { $ticket_id = intval($_GET['reopen_ticket']); // Get ticket details for logging - $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = $ticket_id LIMIT 1")); + $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT ticket_number, ticket_prefix FROM tickets WHERE ticket_id = $ticket_id LIMIT 1")); $ticket_prefix = escapeSql($row['ticket_prefix']); $ticket_number = intval($row['ticket_number']); @@ -312,7 +313,7 @@ if (isset($_GET['close_ticket'])) { $ticket_id = intval($_GET['close_ticket']); // Get ticket details for logging - $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = $ticket_id LIMIT 1")); + $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT ticket_number, ticket_prefix FROM tickets WHERE ticket_id = $ticket_id LIMIT 1")); $ticket_prefix = escapeSql($row['ticket_prefix']); $ticket_number = intval($row['ticket_number']); @@ -481,7 +482,10 @@ if (isset($_GET['add_payment_by_provider'])) { $saved_payment_id = intval($_GET['add_payment_by_provider']); // Get invoice details - $sql = mysqli_query($mysqli,"SELECT * FROM invoices + $sql = mysqli_query($mysqli,"SELECT client_id, client_name, contact_email, contact_extension, contact_mobile, + contact_mobile_country_code, contact_name, contact_phone, contact_phone_country_code, + invoice_amount, invoice_currency_code, invoice_number, invoice_prefix, invoice_status, + invoice_url_key FROM invoices LEFT JOIN clients ON invoice_client_id = client_id LEFT JOIN contacts ON client_id = contact_client_id AND contact_primary = 1 WHERE invoice_id = $invoice_id AND client_id = $session_client_id" @@ -503,7 +507,8 @@ if (isset($_GET['add_payment_by_provider'])) { $contact_mobile = escapeSql(formatPhoneNumber($row['contact_mobile'], $row['contact_mobile_country_code'])); // Get ITFlow company details - $sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1"); + $sql = mysqli_query($mysqli,"SELECT company_address, company_city, company_country, company_email, company_name, company_phone, + company_phone_country_code, company_state, company_website, company_zip FROM companies WHERE company_id = 1"); $row = mysqli_fetch_assoc($sql); $company_name = escapeSql($row['company_name']); $company_country = escapeSql($row['company_country']); @@ -520,7 +525,9 @@ if (isset($_GET['add_payment_by_provider'])) { $config_invoice_from_email = escapeSql($config_invoice_from_email); // Get Client Payment Details - $sql = mysqli_query($mysqli, "SELECT * FROM client_saved_payment_methods LEFT JOIN payment_providers ON saved_payment_provider_id = payment_provider_id LEFT JOIN client_payment_provider ON saved_payment_client_id = client_id WHERE saved_payment_id = $saved_payment_id AND saved_payment_client_id = $session_client_id LIMIT 1"); + $sql = mysqli_query($mysqli, "SELECT payment_provider_account, payment_provider_client, payment_provider_private_key, + payment_provider_public_key, saved_payment_client_id, saved_payment_description, + saved_payment_provider_method FROM client_saved_payment_methods LEFT JOIN payment_providers ON saved_payment_provider_id = payment_provider_id LEFT JOIN client_payment_provider ON saved_payment_client_id = client_id WHERE saved_payment_id = $saved_payment_id AND saved_payment_client_id = $session_client_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $public_key = escapeSql($row['payment_provider_public_key']); @@ -671,7 +678,7 @@ if (isset($_POST['create_stripe_customer'])) { // Get Stripe provider $stripe_provider_result = mysqli_query($mysqli, " - SELECT * FROM payment_providers + SELECT payment_provider_id, payment_provider_private_key FROM payment_providers WHERE payment_provider_name = 'Stripe' AND payment_provider_active = 1 LIMIT 1 @@ -759,7 +766,7 @@ if (isset($_GET['create_stripe_checkout'])) { // Fetch Stripe provider info $stripe_provider_result = mysqli_query($mysqli, " - SELECT * FROM payment_providers + SELECT payment_provider_id, payment_provider_private_key FROM payment_providers WHERE payment_provider_name = 'Stripe' AND payment_provider_active = 1 LIMIT 1 @@ -842,7 +849,7 @@ if (isset($_GET['stripe_save_card'])) { // Get Stripe provider $stripe_provider_result = mysqli_query($mysqli, " - SELECT * FROM payment_providers + SELECT payment_provider_id, payment_provider_private_key FROM payment_providers WHERE payment_provider_name = 'Stripe' AND payment_provider_active = 1 LIMIT 1 @@ -925,7 +932,8 @@ if (isset($_GET['stripe_save_card'])) { // Email Confirmation $sql_settings = mysqli_query($mysqli, " - SELECT * FROM companies, settings + SELECT company_name, company_phone, company_phone_country_code, config_invoice_from_email, + config_invoice_from_name, config_smtp_host FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1 "); @@ -973,7 +981,7 @@ if (isset($_GET['delete_saved_payment'])) { // Get Stripe provider info $stripe_provider_result = mysqli_query($mysqli, " - SELECT * FROM payment_providers + SELECT payment_provider_id, payment_provider_private_key FROM payment_providers WHERE payment_provider_name = 'Stripe' AND payment_provider_active = 1 LIMIT 1 @@ -1073,7 +1081,8 @@ if (isset($_POST['set_recurring_payment'])) { $saved_payment_id = intval($_POST['saved_payment_id']); // Get Recurring Invoice Info for logging and alerting - $sql = mysqli_query($mysqli, "SELECT * FROM recurring_invoices WHERE recurring_invoice_id = $recurring_invoice_id AND recurring_invoice_client_id = $session_client_id"); + $sql = mysqli_query($mysqli, "SELECT recurring_invoice_amount, recurring_invoice_currency_code, recurring_invoice_number, + recurring_invoice_prefix FROM recurring_invoices WHERE recurring_invoice_id = $recurring_invoice_id AND recurring_invoice_client_id = $session_client_id"); $row = mysqli_fetch_assoc($sql); $recurring_invoice_prefix = escapeSql($row['recurring_invoice_prefix']); $recurring_invoice_number = intval($row['recurring_invoice_number']); @@ -1084,7 +1093,8 @@ if (isset($_POST['set_recurring_payment'])) { // Get Payment provider and method $sql = mysqli_query($mysqli, " - SELECT * FROM payment_providers + SELECT payment_provider_account, payment_provider_id, payment_provider_name, + saved_payment_description FROM payment_providers LEFT JOIN client_saved_payment_methods ON saved_payment_provider_id = payment_provider_id WHERE saved_payment_id = $saved_payment_id AND saved_payment_client_id = $session_client_id diff --git a/client/recurring_invoices.php b/client/recurring_invoices.php index bdec469ea..a65b94d40 100644 --- a/client/recurring_invoices.php +++ b/client/recurring_invoices.php @@ -19,7 +19,7 @@ $recurring_invoices_sql = mysqli_query($mysqli, "SELECT * FROM recurring_invoice ); // Get Payment Provide Details -$payment_provider_sql = mysqli_query($mysqli, "SELECT * FROM payment_providers WHERE payment_provider_active = 1 LIMIT 1"); +$payment_provider_sql = mysqli_query($mysqli, "SELECT payment_provider_id, payment_provider_name, payment_provider_threshold FROM payment_providers WHERE payment_provider_active = 1 LIMIT 1"); $row = mysqli_fetch_assoc($payment_provider_sql); $payment_provider_id = intval($row['payment_provider_id']); $payment_provider_name = escapeHtml($row['payment_provider_name']); @@ -74,7 +74,7 @@ $payment_provider_threshold = floatval($row['payment_provider_threshold']); ly - 0) { ?> diff --git a/client/saved_payment_methods.php b/client/saved_payment_methods.php index 0f82c70e6..89b02c800 100644 --- a/client/saved_payment_methods.php +++ b/client/saved_payment_methods.php @@ -12,7 +12,7 @@ require_once '../includes/stripe_init.php'; // Get Stripe provider info $stripe_provider_query = mysqli_query($mysqli, " - SELECT * FROM payment_providers WHERE payment_provider_name = 'Stripe' LIMIT 1 + SELECT payment_provider_id, payment_provider_private_key, payment_provider_public_key FROM payment_providers WHERE payment_provider_name = 'Stripe' LIMIT 1 "); $stripe_provider = mysqli_fetch_assoc($stripe_provider_query); @@ -28,7 +28,7 @@ $stripe_secret_key = escapeHtml($stripe_provider['payment_provider_private_key'] // Get client's Stripe customer ID $stripe_customer_query = mysqli_query($mysqli, " - SELECT * FROM client_payment_provider + SELECT payment_provider_client FROM client_payment_provider WHERE client_id = $session_client_id AND payment_provider_id = $stripe_provider_id LIMIT 1 "); diff --git a/client/ticket.php b/client/ticket.php index 944039085..0b100a4a2 100644 --- a/client/ticket.php +++ b/client/ticket.php @@ -53,7 +53,7 @@ if (isset($_GET['id']) && intval($_GET['id'])) { // Get Ticket Attachments (not associated with a specific reply) $sql_ticket_attachments = mysqli_query( $mysqli, - "SELECT * FROM ticket_attachments + "SELECT ticket_attachment_id, ticket_attachment_name FROM ticket_attachments WHERE ticket_attachment_reply_id IS NULL AND ticket_attachment_ticket_id = $ticket_id" ); @@ -297,7 +297,7 @@ if (isset($_GET['id']) && intval($_GET['id'])) { // Get attachments for this reply $sql_ticket_reply_attachments = mysqli_query( $mysqli, - "SELECT * FROM ticket_attachments + "SELECT ticket_attachment_id, ticket_attachment_name FROM ticket_attachments WHERE ticket_attachment_reply_id = $ticket_reply_id AND ticket_attachment_ticket_id = $ticket_id" ); diff --git a/client/unpaid_invoices.php b/client/unpaid_invoices.php index 5aed26928..e509a8d29 100644 --- a/client/unpaid_invoices.php +++ b/client/unpaid_invoices.php @@ -17,7 +17,7 @@ $invoices_sql = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_clie // Payment Provider Active Query -$sql_payment_provider = mysqli_query($mysqli, "SELECT * FROM payment_providers WHERE payment_provider_active = 1 LIMIT 1;"); +$sql_payment_provider = mysqli_query($mysqli, "SELECT payment_provider_active, payment_provider_id, payment_provider_threshold FROM payment_providers WHERE payment_provider_active = 1 LIMIT 1;"); $row = mysqli_fetch_assoc($sql_payment_provider); $payment_provider_id = intval($row['payment_provider_id']); $payment_provider_active = intval($row['payment_provider_active']); @@ -25,7 +25,7 @@ $payment_provider_threshold = floatval($row['payment_provider_threshold']); // Saved Payment Methods $sql_saved_payment_methods = mysqli_query($mysqli, " - SELECT * FROM client_saved_payment_methods + SELECT payment_provider_name, saved_payment_description, saved_payment_id FROM client_saved_payment_methods LEFT JOIN payment_providers ON client_saved_payment_methods.saved_payment_provider_id = payment_providers.payment_provider_id WHERE saved_payment_client_id = $session_client_id @@ -156,7 +156,7 @@ $balance = $invoice_amounts - $amount_paid; NOW() LIMIT 1"); + $sql = mysqli_query($mysqli, "SELECT item_active, item_client_id, item_related_id, item_type, item_view_limit, item_views FROM shared_items WHERE item_id = $item_id AND item_key = '$item_key' AND item_expire_at > NOW() LIMIT 1"); $row = mysqli_fetch_assoc($sql); $item_active = intval($row['item_active']); @@ -49,7 +49,7 @@ if (isset($_GET['id']) && isset($_GET['key'])) { } } - $file_sql = mysqli_query($mysqli, "SELECT * FROM files WHERE file_id = $item_related_id AND file_client_id = $client_id LIMIT 1"); + $file_sql = mysqli_query($mysqli, "SELECT file_client_id, file_name, file_reference_name FROM files WHERE file_id = $item_related_id AND file_client_id = $client_id LIMIT 1"); $file_row = mysqli_fetch_assoc($file_sql); if (mysqli_num_rows($file_sql) !== 1 || !$file_row) { diff --git a/guest/guest_pay_invoice_stripe.php b/guest/guest_pay_invoice_stripe.php index bd01f16c9..adf94050b 100644 --- a/guest/guest_pay_invoice_stripe.php +++ b/guest/guest_pay_invoice_stripe.php @@ -5,7 +5,7 @@ require_once 'includes/inc_all_guest.php'; DEFINE("WORDING_PAYMENT_FAILED", "

There was an error verifying your payment. Please contact us for more information before attempting payment again.

"); // --- Get Stripe config from payment_providers table --- -$stripe_provider = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM payment_providers")); +$stripe_provider = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT payment_provider_account, payment_provider_private_key, payment_provider_public_key FROM payment_providers")); $stripe_publishable = escapeHtml($stripe_provider['payment_provider_public_key']); @@ -21,7 +21,9 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent // Query invoice details $sql = mysqli_query( $mysqli, - "SELECT * FROM invoices + "SELECT client_id, client_name, invoice_amount, invoice_currency_code, invoice_date, + invoice_discount_amount, invoice_due, invoice_id, invoice_number, invoice_prefix, + invoice_status FROM invoices LEFT JOIN clients ON invoice_client_id = client_id WHERE invoice_id = $invoice_id AND invoice_url_key = '$invoice_url_key' @@ -182,7 +184,8 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent // Get/Check invoice (& client/primary contact) $invoice_sql = mysqli_query( $mysqli, - "SELECT * FROM invoices + "SELECT client_id, client_name, contact_email, contact_name, invoice_amount, invoice_currency_code, + invoice_id, invoice_number, invoice_prefix, invoice_url_key FROM invoices LEFT JOIN clients ON invoice_client_id = client_id LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1 WHERE invoice_id = $pi_invoice_id @@ -206,7 +209,7 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent $contact_name = escapeSql($row['contact_name']); $contact_email = escapeSql($row['contact_email']); - $sql_company = mysqli_query($mysqli, "SELECT * FROM companies WHERE company_id = 1"); + $sql_company = mysqli_query($mysqli, "SELECT company_locale, company_name, company_phone FROM companies WHERE company_id = 1"); $row = mysqli_fetch_assoc($sql_company); $company_name = escapeSql($row['company_name']); $company_phone = escapeSql(formatPhoneNumber($row['company_phone'])); @@ -252,7 +255,8 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Payment', log_action = 'Create', log_description = 'Stripe payment of $pi_currency $pi_amount_paid against invoice $invoice_prefix$invoice_number - $pi_id $extended_log_desc', log_ip = '$ip', log_user_agent = '$user_agent', log_client_id = $pi_client_id"); // Email Receipt - $sql_settings = mysqli_query($mysqli, "SELECT * FROM settings WHERE company_id = 1"); + $sql_settings = mysqli_query($mysqli, "SELECT config_invoice_from_email, config_invoice_from_name, + config_invoice_paid_notification_email, config_smtp_host FROM settings WHERE company_id = 1"); $settings = mysqli_fetch_assoc($sql_settings); $config_smtp_host = $settings['config_smtp_host']; diff --git a/guest/guest_post.php b/guest/guest_post.php index ec7a02f43..5dda1dce2 100644 --- a/guest/guest_post.php +++ b/guest/guest_post.php @@ -48,7 +48,9 @@ if (isset($_GET['accept_quote'], $_GET['url_key'])) { $row = mysqli_fetch_assoc($sql_company); $company_name = escapeSql($row['company_name']); - $sql_settings = mysqli_query($mysqli, "SELECT * FROM settings WHERE company_id = 1"); + $sql_settings = mysqli_query($mysqli, "SELECT config_quote_from_email, config_quote_from_name, config_quote_notification_email, + config_smtp_encryption, config_smtp_host, config_smtp_password, config_smtp_port, + config_smtp_username FROM settings WHERE company_id = 1"); $row = mysqli_fetch_assoc($sql_settings); $config_smtp_host = $row['config_smtp_host']; $config_smtp_port = intval($row['config_smtp_port']); @@ -121,7 +123,9 @@ if (isset($_GET['decline_quote'], $_GET['url_key'])) { $row = mysqli_fetch_assoc($sql_company); $company_name = escapeSql($row['company_name']); - $sql_settings = mysqli_query($mysqli, "SELECT * FROM settings WHERE company_id = 1"); + $sql_settings = mysqli_query($mysqli, "SELECT config_quote_from_email, config_quote_from_name, config_quote_notification_email, + config_smtp_encryption, config_smtp_host, config_smtp_password, config_smtp_port, + config_smtp_username FROM settings WHERE company_id = 1"); $row = mysqli_fetch_assoc($sql_settings); $config_smtp_host = $row['config_smtp_host']; $config_smtp_port = intval($row['config_smtp_port']); @@ -253,7 +257,8 @@ if (isset($_GET['approve_ticket_task'])) { $approval_id = intval($_GET['approval_id']); $url_key = escapeSql($_GET['approval_url_key']); - $approval_row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM task_approvals LEFT JOIN tasks on task_id = approval_task_id WHERE approval_id = $approval_id AND approval_task_id = $task_id AND approval_url_key = '$url_key' AND approval_status = 'pending'")); + $approval_row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT approval_created_by, approval_required_user_id, approval_scope, approval_type, task_name, + task_ticket_id FROM task_approvals LEFT JOIN tasks on task_id = approval_task_id WHERE approval_id = $approval_id AND approval_task_id = $task_id AND approval_url_key = '$url_key' AND approval_status = 'pending'")); $task_name = escapeHtml($approval_row['task_name']); $scope = escapeHtml($approval_row['approval_scope']); @@ -287,7 +292,12 @@ if (isset($_GET['export_quote_pdf'])) { $sql = mysqli_query( $mysqli, - "SELECT * FROM quotes + "SELECT client_currency_code, client_id, client_name, client_net_terms, client_website, + contact_email, contact_extension, contact_mobile, contact_mobile_country_code, + contact_phone, contact_phone_country_code, location_address, location_city, + location_country, location_state, location_zip, quote_amount, quote_category_id, + quote_created_at, quote_currency_code, quote_date, quote_discount_amount, quote_expire, + quote_id, quote_note, quote_number, quote_prefix, quote_scope, quote_status, quote_url_key FROM quotes LEFT JOIN clients ON quote_client_id = client_id LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1 LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1 @@ -332,7 +342,9 @@ if (isset($_GET['export_quote_pdf'])) { $client_net_terms = $config_default_net_terms; } - $sql = mysqli_query($mysqli, "SELECT * FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1"); + $sql = mysqli_query($mysqli, "SELECT company_address, company_city, company_country, company_email, settings.company_id, + company_locale, company_logo, company_name, company_phone, company_phone_country_code, + company_state, company_website, company_zip FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1"); $row = mysqli_fetch_assoc($sql); $company_id = intval($row['company_id']); @@ -488,7 +500,13 @@ if (isset($_GET['export_invoice_pdf'])) { $sql = mysqli_query( $mysqli, - "SELECT * FROM invoices + "SELECT client_currency_code, client_id, client_name, client_net_terms, client_website, + contact_email, contact_extension, contact_mobile, contact_mobile_country_code, + contact_phone, contact_phone_country_code, invoice_amount, invoice_category_id, + invoice_created_at, invoice_currency_code, invoice_date, invoice_discount_amount, + invoice_due, invoice_id, invoice_note, invoice_number, invoice_prefix, invoice_scope, + invoice_status, invoice_url_key, location_address, location_city, location_country, + location_state, location_zip FROM invoices LEFT JOIN clients ON invoice_client_id = client_id LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1 LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1 @@ -533,7 +551,9 @@ if (isset($_GET['export_invoice_pdf'])) { $client_net_terms = $config_default_net_terms; } - $sql = mysqli_query($mysqli, "SELECT * FROM companies WHERE company_id = 1"); + $sql = mysqli_query($mysqli, "SELECT company_address, company_city, company_country, company_email, company_id, company_locale, + company_logo, company_name, company_phone, company_phone_country_code, company_state, + company_tax_id, company_website, company_zip FROM companies WHERE company_id = 1"); $row = mysqli_fetch_assoc($sql); $company_id = intval($row['company_id']); $company_name = escapeHtml($row['company_name']); @@ -757,7 +777,7 @@ if (isset($_POST['guest_quote_upload_file'])) { $dest_path = $upload_file_dir . $file_reference_name; // Get/Create a top-level folder called Client Uploads - $folder_sql = mysqli_query($mysqli, "SELECT * FROM folders WHERE folder_name = 'Client Uploads' AND parent_folder = 0 AND folder_client_id = $client_id LIMIT 1"); + $folder_sql = mysqli_query($mysqli, "SELECT folder_id FROM folders WHERE folder_name = 'Client Uploads' AND parent_folder = 0 AND folder_client_id = $client_id LIMIT 1"); if (mysqli_num_rows($folder_sql) == 1) { // Get $row = mysqli_fetch_assoc($folder_sql); diff --git a/guest/guest_view_invoice.php b/guest/guest_view_invoice.php index 993a200b6..62a03ff31 100644 --- a/guest/guest_view_invoice.php +++ b/guest/guest_view_invoice.php @@ -14,7 +14,12 @@ $invoice_id = intval($_GET['invoice_id']); $sql = mysqli_query( $mysqli, - "SELECT * FROM invoices + "SELECT client_currency_code, client_id, client_name, client_net_terms, client_website, + contact_email, contact_extension, contact_mobile, contact_mobile_country_code, + contact_phone, contact_phone_country_code, invoice_amount, invoice_category_id, + invoice_currency_code, invoice_date, invoice_discount_amount, invoice_due, invoice_id, + invoice_note, invoice_number, invoice_prefix, invoice_status, location_address, + location_city, location_country, location_state, location_zip FROM invoices LEFT JOIN clients ON invoice_client_id = client_id LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1 LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1 @@ -61,7 +66,9 @@ $client_website = escapeHtml($row['client_website']); $client_currency_code = escapeHtml($row['client_currency_code']); $client_net_terms = intval($row['client_net_terms']); -$sql = mysqli_query($mysqli, "SELECT * FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1"); +$sql = mysqli_query($mysqli, "SELECT company_address, company_city, company_country, company_email, company_locale, + company_logo, company_name, company_phone, company_phone_country_code, company_state, + company_tax_id, company_website, company_zip, config_invoice_footer FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1"); $row = mysqli_fetch_assoc($sql); $company_name = escapeHtml($row['company_name']); @@ -88,7 +95,7 @@ $company_locale = escapeHtml($row['company_locale']); $config_invoice_footer = escapeHtml($row['config_invoice_footer']); // Get Payment Provide Details -$sql = mysqli_query($mysqli, "SELECT * FROM payment_providers WHERE payment_provider_active = 1 LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT payment_provider_id, payment_provider_name, payment_provider_threshold FROM payment_providers WHERE payment_provider_active = 1 LIMIT 1"); $row = mysqli_fetch_assoc($sql); $payment_provider_id = intval($row['payment_provider_id']); $payment_provider_name = escapeHtml($row['payment_provider_name']); diff --git a/guest/guest_view_item.php b/guest/guest_view_item.php index f513c5161..1515f63fd 100644 --- a/guest/guest_view_item.php +++ b/guest/guest_view_item.php @@ -15,7 +15,9 @@ $purifier_config->set('Cache.DefinitionImpl', null); // Disable cache by setting $purifier_config->set('URI.AllowedSchemes', ['data' => true, 'src' => true, 'http' => true, 'https' => true]); $purifier = new HTMLPurifier($purifier_config); -$sql = mysqli_query($mysqli, "SELECT * FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1"); +$sql = mysqli_query($mysqli, "SELECT company_address, company_city, company_email, company_locale, company_logo, company_name, + company_phone, company_phone_country_code, company_state, company_website, company_zip, + config_invoice_footer FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1"); $row = mysqli_fetch_assoc($sql); $company_name = escapeHtml($row['company_name']); @@ -47,7 +49,9 @@ if (!isset($_GET['id']) || !isset($_GET['key'])) { $item_id = intval($_GET['id']); $item_key = escapeSql($_GET['key']); -$sql = mysqli_query($mysqli, "SELECT * FROM shared_items WHERE item_id = $item_id AND item_key = '$item_key' AND item_expire_at > NOW() LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT item_active, item_client_id, item_created_at, item_encrypted_credential, + item_encrypted_username, item_expire_at, item_note, item_recipient, item_related_id, + item_type, item_view_limit, item_views FROM shared_items WHERE item_id = $item_id AND item_key = '$item_key' AND item_expire_at > NOW() LIMIT 1"); $row = mysqli_fetch_assoc($sql); // Check we got a result @@ -171,7 +175,7 @@ if ($item_type == "Document") { } elseif ($item_type == "Credential") { $encryption_key = $_GET['ek']; - $credential_sql = mysqli_query($mysqli, "SELECT * FROM credentials WHERE credential_id = $item_related_id AND credential_client_id = $client_id LIMIT 1"); + $credential_sql = mysqli_query($mysqli, "SELECT credential_id, credential_name, credential_note, credential_otp_secret, credential_uri FROM credentials WHERE credential_id = $item_related_id AND credential_client_id = $client_id LIMIT 1"); $credential_row = mysqli_fetch_assoc($credential_sql); if (mysqli_num_rows($credential_sql) !== 1 || !$credential_row) { echo "
Error retrieving login.
"; diff --git a/guest/guest_view_quote.php b/guest/guest_view_quote.php index f3887b784..e4363843a 100644 --- a/guest/guest_view_quote.php +++ b/guest/guest_view_quote.php @@ -16,7 +16,12 @@ $quote_id = intval($_GET['quote_id']); $sql = mysqli_query( $mysqli, - "SELECT * FROM quotes + "SELECT client_currency_code, client_id, client_name, client_website, contact_email, + contact_extension, contact_mobile, contact_mobile_country_code, contact_phone, + contact_phone_country_code, location_address, location_city, location_country, + location_state, location_zip, quote_amount, quote_currency_code, quote_date, + quote_discount_amount, quote_expire, quote_id, quote_note, quote_number, quote_prefix, + quote_status FROM quotes LEFT JOIN clients ON quote_client_id = client_id LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1 LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1 @@ -61,7 +66,9 @@ $contact_mobile = escapeHtml(formatPhoneNumber($row['contact_mobile'], $contact_ $client_website = escapeHtml($row['client_website']); $client_currency_code = escapeHtml($row['client_currency_code']); -$sql = mysqli_query($mysqli, "SELECT * FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1"); +$sql = mysqli_query($mysqli, "SELECT company_address, company_city, company_country, company_email, company_locale, + company_logo, company_name, company_phone, company_phone_country_code, company_state, + company_website, company_zip, config_quote_footer FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1"); $row = mysqli_fetch_assoc($sql); $company_name = escapeHtml($row['company_name']); $company_address = escapeHtml($row['company_address']); diff --git a/includes/load_company_settings.php b/includes/load_company_settings.php index e4b86a54a..722010c94 100644 --- a/includes/load_company_settings.php +++ b/includes/load_company_settings.php @@ -1,5 +1,5 @@ Date: Thu, 6 Aug 2026 13:44:02 -0400 Subject: [PATCH 09/25] Move more select * to column select for further optimization --- CONTRIBUTING.md | 24 +++++++++++++++++++++-- admin/ai_providers.php | 2 +- admin/modals/user/user_archive.php | 4 ++-- admin/payment_providers.php | 3 ++- admin/users.php | 3 ++- agent/accounts.php | 2 +- agent/asset.php | 6 ++++-- agent/assets.php | 2 +- agent/contact.php | 4 +++- agent/dashboard.php | 2 +- agent/invoice.php | 5 ++--- agent/modals/asset/asset.php | 4 +++- agent/modals/contact/contact.php | 2 +- agent/modals/payment/payment_add.php | 2 +- agent/modals/payment/payment_bulk_add.php | 2 +- agent/modals/payment/payment_edit.php | 2 +- agent/modals/revenue/revenue_add.php | 2 +- agent/modals/revenue/revenue_edit.php | 2 +- agent/modals/transfer/transfer_add.php | 4 ++-- agent/modals/transfer/transfer_edit.php | 4 ++-- agent/post/asset.php | 4 ++-- agent/post/client.php | 4 ++-- agent/post/contact.php | 2 +- agent/post/credential.php | 2 +- agent/post/location.php | 2 +- agent/post/project.php | 3 ++- agent/post/rack.php | 2 +- agent/post/recurring_invoice.php | 3 ++- agent/project.php | 11 +++++++---- agent/projects.php | 4 +++- agent/recurring_invoices.php | 8 +++++++- agent/reports/profit_loss.php | 4 ++-- agent/software.php | 4 +++- client/recurring_invoices.php | 5 ++++- client/ticket.php | 4 ++-- client/unpaid_invoices.php | 3 ++- cron/nightly_tasks.php | 13 ++++++++++-- 37 files changed, 107 insertions(+), 52 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ac74a5b51..5cf36d651 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -178,7 +178,8 @@ A user can be restricted to a subset of clients through `user_client_permissions **A list — `clientScopeSql()`.** Any query returning more than one row appends the fragment for that resource's own client column: ```php -$sql = mysqli_query($mysqli, "SELECT * FROM expenses +$sql = mysqli_query($mysqli, "SELECT expense_id, expense_date, expense_amount, expense_description + FROM expenses WHERE expense_archived_at IS NULL " . clientScopeSql('expense_client_id') . " ORDER BY expense_date DESC"); @@ -224,7 +225,26 @@ Per [SECURITY.md](SECURITY.md) — never in a public issue. ## Conventions -**Database naming.** Every column is prefixed with the singular name of the entity it belongs to: `tickets.ticket_id`, `tickets.ticket_subject`, `clients.client_name`. This makes JOIN results unambiguous and is why queries can `SELECT *` across joins safely. New tables must follow it. +**Database naming.** Every column is prefixed with the singular name of the entity it belongs to: `tickets.ticket_id`, `tickets.ticket_subject`, `clients.client_name`. This makes JOIN results unambiguous, so a `SELECT *` across joins is never *wrong*. New tables must follow it. + +**Select the columns you use, not `*`.** Unambiguous is not the same as cheap. `SELECT *` across three joined tables fetches every column of all three, including the `*_notes` and `*_details` TEXT columns, and throws away whatever the page never renders. A search result list that shows five fields was pulling sixty. List the columns instead: + +```php +$sql = mysqli_query($mysqli, "SELECT ticket_id, ticket_prefix, ticket_number, ticket_subject, client_name + FROM tickets + LEFT JOIN clients ON ticket_client_id = client_id + WHERE ticket_archived_at IS NULL + " . clientScopeSql('ticket_client_id') . ""); +``` + +Two things follow from that: + +- A query whose result only feeds `mysqli_num_rows()` needs no columns at all — write `SELECT 1`. Do not select a primary key "just in case": if the query joins two tables that both carry that column name, an unqualified `SELECT ticket_template_id` is an ambiguous-column error. +- Keep the join even when no column of the joined table survives into the `SELECT`, if the join is doing work — supplying a `WHERE` term, an `ORDER BY`, or the client column you scope on. Dropping a join is a separate decision from trimming the column list. + +The trade is real and worth stating: `SELECT *` picks up new columns for free, an explicit list does not. Add a column to a table and every query that needs it must be updated by hand, and the failure mode is a blank field or a PHP 8 undefined-key warning rather than an error. That is the price of not fetching data nobody reads, and the project has decided to pay it on anything that loops or touches a TEXT column. + +The exception is `api/v1/*/read.php`. Those endpoints hand the whole row to `read_output.php`, which serialises it straight into the JSON response — there the row *is* the output contract, so `SELECT *` is correct and trimming it would silently drop fields from every consumer. The prefix is the entity name, which is usually but not always the singular of the table name. Where a table is named for its container rather than its row, the prefix follows the row: `calendar_events` → `event_*`, `asset_interfaces` → `interface_*`, `invoice_items` / `quote_items` → `item_*`, `rack_units` → `unit_*`, `user_roles` → `role_*`, `product_stock` → `stock_*`. Pick the prefix your columns will read best as and use it for every column in the table. diff --git a/admin/ai_providers.php b/admin/ai_providers.php index 3bb6b5729..b9b728314 100644 --- a/admin/ai_providers.php +++ b/admin/ai_providers.php @@ -6,7 +6,7 @@ $order = "ASC"; require_once "includes/inc_all_admin.php"; -$sql = mysqli_query($mysqli, "SELECT * FROM ai_providers ORDER BY $sort $order"); +$sql = mysqli_query($mysqli, "SELECT ai_provider_api_key, ai_provider_api_url, ai_provider_id, ai_provider_name FROM ai_providers ORDER BY $sort $order"); $num_rows = mysqli_num_rows($sql); diff --git a/admin/modals/user/user_archive.php b/admin/modals/user/user_archive.php index 02637e8d9..f93205894 100644 --- a/admin/modals/user/user_archive.php +++ b/admin/modals/user/user_archive.php @@ -12,13 +12,13 @@ $user_email = escapeHtml($row['user_email']); $user_avatar = escapeHtml($row['user_avatar']); $user_initials = escapeHtml(initials($user_name)); -$sql_related_tickets = mysqli_query($mysqli, "SELECT * FROM tickets +$sql_related_tickets = mysqli_query($mysqli, "SELECT 1 FROM tickets WHERE ticket_assigned_to = $user_id AND ticket_resolved_at IS NULL AND ticket_closed_at IS NULL"); $ticket_count = mysqli_num_rows($sql_related_tickets); // Related Recurring Tickets Query -$sql_related_recurring_tickets = mysqli_query($mysqli, "SELECT * FROM recurring_tickets WHERE recurring_ticket_assigned_to = $user_id"); +$sql_related_recurring_tickets = mysqli_query($mysqli, "SELECT 1 FROM recurring_tickets WHERE recurring_ticket_assigned_to = $user_id"); $recurring_ticket_count = mysqli_num_rows($sql_related_recurring_tickets); diff --git a/admin/payment_providers.php b/admin/payment_providers.php index e80a62ea3..0f7545f03 100644 --- a/admin/payment_providers.php +++ b/admin/payment_providers.php @@ -6,7 +6,8 @@ $order = "ASC"; require_once "includes/inc_all_admin.php"; -$sql = mysqli_query($mysqli, "SELECT * FROM payment_providers +$sql = mysqli_query($mysqli, "SELECT account_name, category_name, payment_provider_description, payment_provider_id, + payment_provider_name, payment_provider_threshold, vendor_name FROM payment_providers LEFT JOIN accounts ON payment_provider_account = account_id LEFT JOIN vendors ON payment_provider_expense_vendor = vendor_id LEFT JOIN categories ON payment_provider_expense_category = category_id diff --git a/admin/users.php b/admin/users.php index 14e49f3d5..954ae331e 100644 --- a/admin/users.php +++ b/admin/users.php @@ -8,7 +8,8 @@ require_once "includes/inc_all_admin.php"; $sql = mysqli_query( $mysqli, - "SELECT SQL_CALC_FOUND_ROWS * FROM users + "SELECT SQL_CALC_FOUND_ROWS role_name, user_archived_at, user_avatar, user_config_force_mfa, user_email, + user_settings.user_id, user_name, user_role_id, user_status, user_token FROM users LEFT JOIN user_roles ON user_role_id = role_id LEFT JOIN user_settings ON users.user_id = user_settings.user_id WHERE (user_name LIKE '%$q%' OR user_email LIKE '%$q%') diff --git a/agent/accounts.php b/agent/accounts.php index ef8301d71..bae78d76b 100644 --- a/agent/accounts.php +++ b/agent/accounts.php @@ -11,7 +11,7 @@ enforceUserPermission('module_financial'); $sql = mysqli_query( $mysqli, - "SELECT SQL_CALC_FOUND_ROWS * FROM accounts + "SELECT SQL_CALC_FOUND_ROWS account_currency_code, account_id, account_name, account_notes, opening_balance FROM accounts WHERE (account_name LIKE '%$q%') AND account_archived_at IS NULL ORDER BY $sort $order LIMIT $record_from, $record_to" diff --git a/agent/asset.php b/agent/asset.php index 2e8e20976..d7e0e3bdc 100644 --- a/agent/asset.php +++ b/agent/asset.php @@ -122,7 +122,7 @@ if (isset($_GET['asset_id'])) { $recurring_ticket_count = mysqli_num_rows($sql_related_recurring_tickets); // Related Documents - $sql_related_documents = mysqli_query($mysqli, "SELECT * FROM asset_documents + $sql_related_documents = mysqli_query($mysqli, "SELECT 1 FROM asset_documents LEFT JOIN documents ON asset_documents.document_id = documents.document_id WHERE asset_documents.asset_id = $asset_id AND document_archived_at IS NULL @@ -252,7 +252,9 @@ if (isset($_GET['asset_id'])) { // Related Software Query $sql_related_software = mysqli_query( $mysqli, - "SELECT * FROM software_assets + "SELECT software_expire, software_assets.software_id, software_key, software_license_type, + software_name, software_notes, software_purchase, software_seats, software_type, + software_version FROM software_assets LEFT JOIN software ON software_assets.software_id = software.software_id WHERE software_assets.asset_id = $asset_id AND software_archived_at IS NULL diff --git a/agent/assets.php b/agent/assets.php index c80b2a093..1705d0ade 100644 --- a/agent/assets.php +++ b/agent/assets.php @@ -641,7 +641,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $location_name_display = $location_name; } - $sql_credentials = mysqli_query($mysqli, "SELECT * FROM credentials WHERE credential_asset_id = $asset_id"); + $sql_credentials = mysqli_query($mysqli, "SELECT 1 FROM credentials WHERE credential_asset_id = $asset_id"); $credential_count = mysqli_num_rows($sql_credentials); // Tags diff --git a/agent/contact.php b/agent/contact.php index 2db7bee17..fc7aca669 100644 --- a/agent/contact.php +++ b/agent/contact.php @@ -83,7 +83,9 @@ if (isset($_GET['contact_id'])) { $asset_count = mysqli_num_rows($sql_related_assets); // Linked Software Licenses - $sql_linked_software = mysqli_query($mysqli, "SELECT * FROM software_contacts, software + $sql_linked_software = mysqli_query($mysqli, "SELECT software_expire, software_contacts.software_id, software_key, software_license_type, + software_name, software_notes, software_purchase, software_seats, software_type, + software_version FROM software_contacts, software WHERE software_contacts.contact_id = $contact_id AND software_contacts.software_id = software.software_id AND software_archived_at IS NULL diff --git a/agent/dashboard.php b/agent/dashboard.php index 237a497b1..61f336696 100644 --- a/agent/dashboard.php +++ b/agent/dashboard.php @@ -117,7 +117,7 @@ if ($user_config_dashboard_financial_enable == 1) { $profit = $total_income - $total_expenses; - $sql_accounts = mysqli_query($mysqli, "SELECT * FROM accounts WHERE account_archived_at IS NULL ORDER BY account_name ASC"); + $sql_accounts = mysqli_query($mysqli, "SELECT account_id, account_name, opening_balance FROM accounts WHERE account_archived_at IS NULL ORDER BY account_name ASC"); $sql_latest_invoice_payments = mysqli_query($mysqli, " SELECT client_name, invoice_number, invoice_prefix, payment_amount, payment_date FROM payments diff --git a/agent/invoice.php b/agent/invoice.php index c4129a555..660151858 100644 --- a/agent/invoice.php +++ b/agent/invoice.php @@ -130,8 +130,7 @@ if (isset($_GET['invoice_id'])) { //Get billable, and unbilled tickets to add to invoice $sql_tickets_billable = mysqli_query( $mysqli, " - SELECT - * + SELECT 1 FROM tickets WHERE @@ -199,7 +198,7 @@ if (isset($_GET['invoice_id'])) { // Saved Payment Methods $sql_saved_payment_methods = mysqli_query($mysqli, " - SELECT * FROM client_saved_payment_methods + SELECT 1 FROM client_saved_payment_methods LEFT JOIN payment_providers ON client_saved_payment_methods.saved_payment_provider_id = payment_providers.payment_provider_id WHERE saved_payment_client_id = $client_id diff --git a/agent/modals/asset/asset.php b/agent/modals/asset/asset.php index 7ad997ff0..0922e67fe 100644 --- a/agent/modals/asset/asset.php +++ b/agent/modals/asset/asset.php @@ -219,7 +219,9 @@ $file_count = mysqli_num_rows($sql_related_files); // Related Software Query $sql_related_software = mysqli_query( $mysqli, - "SELECT * FROM software_assets + "SELECT software_expire, software_assets.software_id, software_key, software_license_type, + software_name, software_notes, software_purchase, software_seats, software_type, + software_version FROM software_assets LEFT JOIN software ON software_assets.software_id = software.software_id WHERE software_assets.asset_id = $asset_id AND software_archived_at IS NULL diff --git a/agent/modals/contact/contact.php b/agent/modals/contact/contact.php index e495ac928..c0027ac40 100644 --- a/agent/modals/contact/contact.php +++ b/agent/modals/contact/contact.php @@ -158,7 +158,7 @@ while ($row = mysqli_fetch_assoc($sql_note_type_icons)) { } // Linked Services -$sql_linked_services = mysqli_query($mysqli, "SELECT * FROM service_contacts, services +$sql_linked_services = mysqli_query($mysqli, "SELECT 1 FROM service_contacts, services WHERE service_contacts.contact_id = $contact_id AND service_contacts.service_id = services.service_id ORDER BY service_name ASC" diff --git a/agent/modals/payment/payment_add.php b/agent/modals/payment/payment_add.php index 9845d9456..42862cf43 100644 --- a/agent/modals/payment/payment_add.php +++ b/agent/modals/payment/payment_add.php @@ -93,7 +93,7 @@ ob_start(); - Select an Account - - Select an Account - - Account - - Select Account - '$revenue_created_at' OR account_archived_at IS NULL) ORDER BY account_archived_at ASC, account_name ASC"); + $sql_accounts = mysqli_query($mysqli, "SELECT account_archived_at, account_currency_code, account_id, account_name, opening_balance FROM accounts WHERE (account_archived_at > '$revenue_created_at' OR account_archived_at IS NULL) ORDER BY account_archived_at ASC, account_name ASC"); while ($row = mysqli_fetch_assoc($sql_accounts)) { $account_id_select = intval($row['account_id']); $account_name_select = escapeHtml($row['account_name']); diff --git a/agent/modals/transfer/transfer_add.php b/agent/modals/transfer/transfer_add.php index 1b0a84ff8..10217e7dc 100644 --- a/agent/modals/transfer/transfer_add.php +++ b/agent/modals/transfer/transfer_add.php @@ -50,7 +50,7 @@ ob_start(); - Account To - '$transfer_created_at' OR account_archived_at IS NULL) ORDER BY account_archived_at ASC, account_name ASC"); + $sql_accounts = mysqli_query($mysqli, "SELECT account_archived_at, account_id, account_name, opening_balance FROM accounts WHERE (account_archived_at > '$transfer_created_at' OR account_archived_at IS NULL) ORDER BY account_archived_at ASC, account_name ASC"); while ($row = mysqli_fetch_assoc($sql_accounts)) { $account_id_select = intval($row['account_id']); $account_name_select = escapeHtml($row['account_name']); @@ -119,7 +119,7 @@ ob_start(); + @@ -26,7 +26,7 @@
  • - + @@ -35,7 +35,7 @@
  • - + @@ -44,7 +44,7 @@
  • - + @@ -53,7 +53,7 @@
  • - + @@ -62,7 +62,7 @@
  • - + @@ -71,7 +71,7 @@
  • - + @@ -80,7 +80,7 @@
  • - + @@ -89,7 +89,7 @@
  • - + @@ -102,7 +102,7 @@
  • - + @@ -111,7 +111,7 @@
  • - + @@ -120,7 +120,7 @@
  • - + @@ -129,7 +129,7 @@
  • - + @@ -138,7 +138,7 @@
  • - + @@ -147,7 +147,7 @@
  • - + @@ -156,7 +156,7 @@
  • - + @@ -165,7 +165,7 @@
  • - + diff --git a/agent/post/asset.php b/agent/post/asset.php index d04e3bd72..871cb7698 100644 --- a/agent/post/asset.php +++ b/agent/post/asset.php @@ -1316,7 +1316,7 @@ if (isset($_GET['download_assets_csv_template'])) { } -if (isset($_POST['export_assets'])) { +if (isExportRequest('export_assets')) { validateCSRFToken(); @@ -2056,7 +2056,7 @@ if (isset($_GET['download_client_asset_interfaces_csv_template'])) { } -if (isset($_POST['export_asset_interfaces'])) { +if (isExportRequest('export_asset_interfaces')) { validateCSRFToken(); diff --git a/agent/post/certificate.php b/agent/post/certificate.php index 9820ce197..8a91aa6b8 100644 --- a/agent/post/certificate.php +++ b/agent/post/certificate.php @@ -338,7 +338,7 @@ if (isset($_POST['bulk_delete_certificates'])) { } -if (isset($_POST['export_certificates'])) { +if (isExportRequest('export_certificates')) { validateCSRFToken(); diff --git a/agent/post/client.php b/agent/post/client.php index e94686e1a..6f4d7b106 100644 --- a/agent/post/client.php +++ b/agent/post/client.php @@ -356,7 +356,7 @@ if (isset($_GET['delete_client'])) { } -if (isset($_POST['export_clients'])) { +if (isExportRequest('export_clients')) { validateCSRFToken(); @@ -1192,26 +1192,26 @@ if (isset($_POST["export_client_pdf"])) { $company_logo = escapeHtml($row['company_logo']); $client_id = intval($_POST["client_id"]); - $export_contacts = intval($_POST["export_contacts"]); - $export_locations = intval($_POST["export_locations"]); - $export_assets = intval($_POST["export_assets"]); - $export_software = intval($_POST["export_software"]); + $export_contacts = intval($_POST["include_contacts"] ?? 0); + $export_locations = intval($_POST["include_locations"] ?? 0); + $export_assets = intval($_POST["include_assets"] ?? 0); + $export_software = intval($_POST["include_software"] ?? 0); $export_credentials = 0; if (lookupUserPermission("module_credential") >= 1) { - $export_credentials = intval($_POST["export_credentials"] ?? 0); + $export_credentials = intval($_POST["include_credentials"] ?? 0); } - $export_networks = intval($_POST["export_networks"]); - $export_certificates = intval($_POST["export_certificates"]); - $export_domains = intval($_POST["export_domains"]); - $export_tickets = intval($_POST["export_tickets"]); - $export_recurring_tickets = intval($_POST["export_recurring_tickets"]); - $export_vendors = intval($_POST["export_vendors"]); - $export_invoices = intval($_POST["export_invoices"]); - $export_recurring_invoices = intval($_POST["export_recurring_invoices"]); - $export_quotes = intval($_POST["export_quotes"]); - $export_payments = intval($_POST["export_payments"]); - $export_trips = intval($_POST["export_trips"]); - $export_logs = intval($_POST["export_logs"]); + $export_networks = intval($_POST["include_networks"] ?? 0); + $export_certificates = intval($_POST["include_certificates"] ?? 0); + $export_domains = intval($_POST["include_domains"] ?? 0); + $export_tickets = intval($_POST["include_tickets"] ?? 0); + $export_recurring_tickets = intval($_POST["include_recurring_tickets"] ?? 0); + $export_vendors = intval($_POST["include_vendors"] ?? 0); + $export_invoices = intval($_POST["include_invoices"] ?? 0); + $export_recurring_invoices = intval($_POST["include_recurring_invoices"] ?? 0); + $export_quotes = intval($_POST["include_quotes"] ?? 0); + $export_payments = intval($_POST["include_payments"] ?? 0); + $export_trips = intval($_POST["include_trips"] ?? 0); + $export_logs = intval($_POST["include_logs"] ?? 0); enforceClientAccess(); diff --git a/agent/post/contact.php b/agent/post/contact.php index edabf6425..ef2c95b9e 100644 --- a/agent/post/contact.php +++ b/agent/post/contact.php @@ -1262,7 +1262,7 @@ if (isset($_GET['unlink_contact_from_file'])) { } -if (isset($_POST['export_contacts'])) { +if (isExportRequest('export_contacts')) { validateCSRFToken(); diff --git a/agent/post/credential.php b/agent/post/credential.php index db7694098..a884a43e6 100644 --- a/agent/post/credential.php +++ b/agent/post/credential.php @@ -410,7 +410,7 @@ if (isset($_POST['bulk_delete_credentials'])) { } -if (isset($_POST['export_credentials'])) { +if (isExportRequest('export_credentials')) { validateCSRFToken(); diff --git a/agent/post/domain.php b/agent/post/domain.php index 60adc8a43..5b3e32c3c 100644 --- a/agent/post/domain.php +++ b/agent/post/domain.php @@ -455,7 +455,7 @@ if (isset($_POST['bulk_refresh_domains'])) { } -if (isset($_POST['export_domains'])) { +if (isExportRequest('export_domains')) { validateCSRFToken(); diff --git a/agent/post/expense.php b/agent/post/expense.php index ce269108e..d2f5c39a6 100644 --- a/agent/post/expense.php +++ b/agent/post/expense.php @@ -298,7 +298,7 @@ if (isset($_POST['bulk_delete_expenses'])) { } -if (isset($_POST['export_expenses'])) { +if (isExportRequest('export_expenses')) { validateCSRFToken(); diff --git a/agent/post/income.php b/agent/post/income.php index 79da2bfa4..c24c04b42 100644 --- a/agent/post/income.php +++ b/agent/post/income.php @@ -307,7 +307,7 @@ if (isset($_POST['bulk_edit_income_method'])) { } -if (isset($_POST['export_income'])) { +if (isExportRequest('export_income')) { validateCSRFToken(); diff --git a/agent/post/invoice.php b/agent/post/invoice.php index 3c5975966..5cc734be5 100644 --- a/agent/post/invoice.php +++ b/agent/post/invoice.php @@ -657,7 +657,7 @@ if (isset($_GET['email_invoice'])) { } -if (isset($_POST['export_invoices'])) { +if (isExportRequest('export_invoices')) { validateCSRFToken(); diff --git a/agent/post/location.php b/agent/post/location.php index 72aab550c..01619678c 100644 --- a/agent/post/location.php +++ b/agent/post/location.php @@ -388,7 +388,7 @@ if (isset($_POST['bulk_delete_locations'])) { } -if (isset($_POST['export_locations'])) { +if (isExportRequest('export_locations')) { validateCSRFToken(); diff --git a/agent/post/network.php b/agent/post/network.php index dbf6c86f6..0e2b1f2c1 100644 --- a/agent/post/network.php +++ b/agent/post/network.php @@ -172,7 +172,7 @@ if (isset($_POST['bulk_delete_networks'])) { } -if (isset($_POST['export_networks'])) { +if (isExportRequest('export_networks')) { validateCSRFToken(); diff --git a/agent/post/product.php b/agent/post/product.php index 56555c4c4..aded5b520 100644 --- a/agent/post/product.php +++ b/agent/post/product.php @@ -244,7 +244,7 @@ if (isset($_POST['bulk_delete_products'])) { } -if (isset($_POST['export_products'])) { +if (isExportRequest('export_products')) { validateCSRFToken(); diff --git a/agent/post/quote.php b/agent/post/quote.php index 2de119994..e41deae9e 100644 --- a/agent/post/quote.php +++ b/agent/post/quote.php @@ -692,7 +692,7 @@ if (isset($_GET['mark_quote_invoiced'])) { } -if (isset($_POST['export_quotes'])) { +if (isExportRequest('export_quotes')) { validateCSRFToken(); diff --git a/agent/post/recurring_invoice.php b/agent/post/recurring_invoice.php index b91678827..62b2c9462 100644 --- a/agent/post/recurring_invoice.php +++ b/agent/post/recurring_invoice.php @@ -617,7 +617,7 @@ if (isset($_POST['set_recurring_payment'])) { } -if (isset($_POST['export_recurring_invoices'])) { +if (isExportRequest('export_recurring_invoices')) { validateCSRFToken(); diff --git a/agent/post/software.php b/agent/post/software.php index 16ebe26e9..ec07d5892 100644 --- a/agent/post/software.php +++ b/agent/post/software.php @@ -226,7 +226,7 @@ if (isset($_GET['delete_software'])) { } -if (isset($_POST['export_software'])) { +if (isExportRequest('export_software')) { validateCSRFToken(); diff --git a/agent/post/ticket.php b/agent/post/ticket.php index 8fb35b1ee..aa6bfb224 100644 --- a/agent/post/ticket.php +++ b/agent/post/ticket.php @@ -2741,7 +2741,7 @@ if (isset($_POST['add_quote_from_ticket'])) { } -if (isset($_POST['export_tickets'])) { +if (isExportRequest('export_tickets')) { validateCSRFToken(); diff --git a/agent/post/transaction.php b/agent/post/transaction.php index 0cdd368c7..15b86683c 100644 --- a/agent/post/transaction.php +++ b/agent/post/transaction.php @@ -9,7 +9,7 @@ if (!defined('FROM_POST_HANDLER')) { exit; } -if (isset($_POST['export_transactions'])) { +if (isExportRequest('export_transactions')) { validateCSRFToken(); diff --git a/agent/post/trip.php b/agent/post/trip.php index 86c6ec71a..9e0cbc87b 100644 --- a/agent/post/trip.php +++ b/agent/post/trip.php @@ -84,7 +84,7 @@ if (isset($_GET['delete_trip'])) { } -if (isset($_POST['export_trips'])) { +if (isExportRequest('export_trips')) { validateCSRFToken(); diff --git a/agent/post/vendor.php b/agent/post/vendor.php index d263a7bb1..ca0bca4f2 100644 --- a/agent/post/vendor.php +++ b/agent/post/vendor.php @@ -353,7 +353,7 @@ if (isset($_POST['bulk_delete_vendors'])) { } -if (isset($_POST['export_vendors'])) { +if (isExportRequest('export_vendors')) { validateCSRFToken(); diff --git a/functions/export.php b/functions/export.php index d80739f29..91e0d0011 100644 --- a/functions/export.php +++ b/functions/export.php @@ -348,6 +348,17 @@ function resolveExportFormat($format) { return ($format === 'pdf') ? 'pdf' : 'csv'; } +/* + * The gate every export handler opens on. Keying on isset() alone means any other + * field that happens to share the trigger's name fires the export - the client PDF + * pack's section checkboxes (export_assets=1, export_contacts=1, ...) did exactly + * that, and since post.php loads every handler, the first match won and streamed a + * CSV instead. Only 'csv' or 'pdf' - what renderExportButtons() posts - counts. + */ +function isExportRequest($trigger) { + return isset($_POST[$trigger]) && in_array($_POST[$trigger], ['csv', 'pdf'], true); +} + /* * PDF is capped - see EXPORT_PDF_MAX_ROWS. Call this after the row count is known * and before beginExport(); it redirects rather than returning on refusal. From 942fe41b18fc7caaa68588bb6c1286319bce1851 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Thu, 6 Aug 2026 19:03:47 -0400 Subject: [PATCH 14/25] Apply further gating to client pdf export --- agent/includes/inc_client_top_head.php | 2 +- agent/modals/client/client_download_pdf.php | 163 +------------------- agent/post/client.php | 118 ++++++-------- functions/export.php | 104 +++++++++++++ 4 files changed, 155 insertions(+), 232 deletions(-) diff --git a/agent/includes/inc_client_top_head.php b/agent/includes/inc_client_top_head.php index 9bf26df13..62075a541 100644 --- a/agent/includes/inc_client_top_head.php +++ b/agent/includes/inc_client_top_head.php @@ -31,7 +31,7 @@ - = 3) { ?> + = 1) { ?> Export Data diff --git a/agent/modals/client/client_download_pdf.php b/agent/modals/client/client_download_pdf.php index 8f0f76e58..81a6aebc2 100644 --- a/agent/modals/client/client_download_pdf.php +++ b/agent/modals/client/client_download_pdf.php @@ -12,168 +12,7 @@
  • +
    + > + +
    +
  • + + +
    +
    + Date: Thu, 6 Aug 2026 19:18:34 -0400 Subject: [PATCH 15/25] Fix AI --- CONTRIBUTING.md | 4 + admin/database_updates/2.6.7.php | 18 +++ admin/modals/ai/ai_model_add.php | 11 ++ admin/modals/ai/ai_model_edit.php | 13 +- admin/post.php | 14 +- admin/post/{ai_model.php => ai_models.php} | 20 ++- agent/ajax.php | 178 +++++++-------------- agent/post.php | 14 +- db.sql | 1 + functions.php | 1 + functions/ai.php | 132 +++++++++++++++ js/app.js | 37 ++++- 12 files changed, 309 insertions(+), 134 deletions(-) create mode 100644 admin/database_updates/2.6.7.php rename admin/post/{ai_model.php => ai_models.php} (60%) create mode 100644 functions/ai.php diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5cf36d651..668c56cc3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -74,6 +74,10 @@ if (isset($_POST['edit_ticket_priority'])) { ### The `_model.php` pattern Files named `agent/post/*_model.php` hold shared field collection/sanitization logic used by both the create and edit blocks of a module (e.g. `asset_model.php` is included by both `add_asset` and `edit_asset`). If create and edit share more than a couple of fields, use this pattern rather than duplicating. Model files carry the same `FROM_POST_HANDLER` guard and are excluded from the dispatcher's auto-load. + +**`_model.php` is a reserved suffix.** The exclusion is a filename match, so a *handler* named `*_model.php` is silently never loaded — its form posts, nothing claims the request, and the user gets a blank page with no error anywhere. This is what happened to `admin/post/ai_model.php`, which is why the AI Models handler is now `admin/post/ai_models.php`. Name entity handlers around the suffix (`ai_models.php`, `users.php`, `api_keys.php`). + +A POST that reaches the end of `admin/post.php` or `agent/post.php` without a handler claiming it is logged to App Logs as a `Request` warning, which is the fastest way to spot this class of mistake. --- diff --git a/admin/database_updates/2.6.7.php b/admin/database_updates/2.6.7.php new file mode 100644 index 000000000..b56a4114f --- /dev/null +++ b/admin/database_updates/2.6.7.php @@ -0,0 +1,18 @@ +
    +
    + +
    +
    + +
    + +
    + Optional. Leave blank to let the provider use its default - some newer models reject every other value. +
    +
    diff --git a/admin/modals/ai/ai_model_edit.php b/admin/modals/ai/ai_model_edit.php index 6f780bf03..05413b98a 100644 --- a/admin/modals/ai/ai_model_edit.php +++ b/admin/modals/ai/ai_model_edit.php @@ -4,13 +4,14 @@ require_once '../../includes/modal_header.php'; $model_id = intval($_GET['id']); -$sql = mysqli_query($mysqli, "SELECT ai_model_ai_provider_id, ai_model_id, ai_model_name, ai_model_prompt, ai_model_use_case FROM ai_models WHERE ai_model_id = $model_id LIMIT 1"); +$sql = mysqli_query($mysqli, "SELECT ai_model_ai_provider_id, ai_model_id, ai_model_name, ai_model_prompt, ai_model_use_case, ai_model_temperature FROM ai_models WHERE ai_model_id = $model_id LIMIT 1"); $row = mysqli_fetch_assoc($sql); $ai_model_ai_provider_id = intval($row['ai_model_ai_provider_id']); $model_id = intval($row['ai_model_id']); $model_name = escapeHtml($row['ai_model_name']); $use_case = escapeHtml($row['ai_model_use_case']); +$temperature = escapeHtml($row['ai_model_temperature']); $prompt = escapeHtml($row['ai_model_prompt']); // Generate the HTML form content using output buffering. @@ -74,6 +75,16 @@ ob_start(); +
    + +
    +
    + +
    + +
    + Optional. Leave blank to let the provider use its default - some newer models reject every other value. +
    diff --git a/admin/post.php b/admin/post.php index 272b8564e..6802e4bfb 100644 --- a/admin/post.php +++ b/admin/post.php @@ -10,7 +10,11 @@ require_once __DIR__ . "/../includes/check_login.php"; // Only allow running post files via inclusion (prevents people/bots poking them directly) define('FROM_POST_HANDLER', true); -// Load all admin module POST logic +// Load all admin module POST logic. +// *_model.php is a RESERVED suffix: those files are not handlers, they are inline +// field-parsing fragments that read $_POST at include time, so the glob must not +// pull them in. A handler named *_model.php is silently never loaded - name entity +// handlers around it (admin/post/ai_models.php, not ai_model.php). if (!empty($session_is_admin)) { foreach (glob(__DIR__ . "/post/*.php") as $admin_module) { if (!str_ends_with($admin_module, '_model.php')) { @@ -22,3 +26,11 @@ if (!empty($session_is_admin)) { // Logout is shared between portals require_once __DIR__ . "/../post/logout.php"; require_once __DIR__ . "/../post/misc.php"; + +// Every handler above exits or redirects, so getting here means no handler claimed +// the request - a blank page and no trace of why. Log it; the usual cause is a +// handler file that never loaded. +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $unhandled = implode(', ', array_slice(array_keys($_POST), 0, 10)); + logApp('Request', 'warning', "Unhandled POST to admin/post.php - no handler matched. Fields: $unhandled"); +} diff --git a/admin/post/ai_model.php b/admin/post/ai_models.php similarity index 60% rename from admin/post/ai_model.php rename to admin/post/ai_models.php index f6ceaddce..cf927ff51 100644 --- a/admin/post/ai_model.php +++ b/admin/post/ai_models.php @@ -1,7 +1,7 @@ $model could not be created - see Admin > App Logs", 'error'); + redirect(); + } logAudit("AI Model", "Create", "$session_name created AI Model $model"); @@ -36,7 +44,11 @@ if (isset($_POST['edit_ai_model'])) { $prompt = escapeSql($_POST['prompt']); $use_case = escapeSql($_POST['use_case']); - mysqli_query($mysqli,"UPDATE ai_models SET ai_model_name = '$model', ai_model_prompt = '$prompt', ai_model_use_case = '$use_case' WHERE ai_model_id = $model_id"); + // Blank means "send no temperature at all" - the only setting that works on every + // provider. Anything else rides as a numeric literal, so no quoting. + $temperature = ($_POST['temperature'] ?? '') === '' ? 'NULL' : floatval($_POST['temperature']); + + mysqli_query($mysqli,"UPDATE ai_models SET ai_model_name = '$model', ai_model_prompt = '$prompt', ai_model_use_case = '$use_case', ai_model_temperature = $temperature WHERE ai_model_id = $model_id"); logAudit("AI Model", "Edit", "$session_name edited AI Model $model"); diff --git a/agent/ajax.php b/agent/ajax.php index b3d961fb9..ee8746a82 100644 --- a/agent/ajax.php +++ b/agent/ajax.php @@ -837,127 +837,88 @@ if (isset($_GET['ai_reword'])) { header('Content-Type: application/json'); - $sql = mysqli_query($mysqli, "SELECT ai_model_name, ai_model_prompt, ai_provider_api_key, ai_provider_api_url FROM ai_models LEFT JOIN ai_providers ON ai_model_ai_provider_id = ai_provider_id WHERE ai_model_use_case = 'General' LIMIT 1"); + // The reword button sits on every TinyMCE instance, so the ticket editor asks for + // the Tickets model and everything else gets General. Anything unrecognised is + // treated as General rather than trusted into the query. + $use_case = ($_GET['use_case'] ?? '') === 'Tickets' ? 'Tickets' : 'General'; - $row = mysqli_fetch_assoc($sql); - $model_name = $row['ai_model_name']; - $promptText = $row['ai_model_prompt']; - $url = $row['ai_provider_api_url']; - $key = $row['ai_provider_api_key']; + $model = getAiModel($use_case); + + if (!$model) { + echo json_encode(['error' => aiModelMissingError($use_case)]); + exit; + } // Collecting the input data from the AJAX request. $inputJSON = file_get_contents('php://input'); $input = json_decode($inputJSON, TRUE); // Convert JSON into array. - $userText = $input['text']; + $userText = $input['text'] ?? ''; - // Preparing the data for the OpenAI Chat API request. - $data = [ - "model" => "$model_name", // Specify the model - "messages" => [ - ["role" => "system", "content" => $promptText], - ["role" => "user", "content" => $userText], - ], - "temperature" => 0.5 - ]; - - // Initialize cURL session to the OpenAI Chat API. - $ch = curl_init("$url"); - - // Set cURL options for the request. - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_POST, true); - curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); - curl_setopt($ch, CURLOPT_HTTPHEADER, [ - 'Content-Type: application/json', - 'Authorization: Bearer ' . $key, + $result = callAiApi($model, [ + ["role" => "system", "content" => $model['ai_model_prompt']], + ["role" => "user", "content" => $userText], ]); - // Execute the cURL session and capture the response. - $response = curl_exec($ch); - curl_close($ch); - - // Decode the JSON response. - $responseData = json_decode($response, true); - - // Check if the response contains the expected data and return it. - if (isset($responseData['choices'][0]['message']['content'])) { - // Get the response content. - $content = $responseData['choices'][0]['message']['content']; - - // Clean any leading "html" word or other unwanted text at the beginning. - $content = preg_replace('/^html/i', '', $content); // Remove any occurrence of 'html' at the start - - // Clean the response content to remove backticks or code block markers. - $cleanedContent = str_replace('```', '', $content); // Remove backticks if they exist. - - // Trim any leading/trailing whitespace. - $cleanedContent = trim($cleanedContent); - - // Return the cleaned response. - echo json_encode(['rewordedText' => $cleanedContent]); - } else { - // Handle errors or unexpected response structure. - echo json_encode(['rewordedText' => 'Failed to get a response from the AI API.']); + // Report failures as an error, never as reworded text - the editor writes + // rewordedText straight back over the user's content + if (!$result['ok']) { + echo json_encode(['error' => $result['error']]); + exit; } + $content = $result['content']; + + // Clean any leading "html" word or other unwanted text at the beginning. + $content = preg_replace('/^html/i', '', $content); // Remove any occurrence of 'html' at the start + + // Clean the response content to remove backticks or code block markers. + $cleanedContent = str_replace('```', '', $content); // Remove backticks if they exist. + + // Trim any leading/trailing whitespace. + $cleanedContent = trim($cleanedContent); + + echo json_encode(['rewordedText' => $cleanedContent]); + } if (isset($_GET['ai_create_document_template'])) { - // get_ai_document_template.php + + enforceUserPermission('module_support'); header('Content-Type: text/html; charset=UTF-8'); - $sql = mysqli_query($mysqli, "SELECT ai_model_name, ai_provider_api_key, ai_provider_api_url FROM ai_models LEFT JOIN ai_providers ON ai_model_ai_provider_id = ai_provider_id WHERE ai_model_use_case = 'General' LIMIT 1"); - - $row = mysqli_fetch_assoc($sql); - $model_name = $row['ai_model_name']; - $url = $row['ai_provider_api_url']; - $key = $row['ai_provider_api_key']; - $prompt = $_POST['prompt'] ?? ''; // Basic validation - if(empty($prompt)){ + if (empty($prompt)) { echo "No prompt provided."; exit; } + $model = getAiModel('Documentation'); + + if (!$model) { + echo escapeHtml(aiModelMissingError('Documentation')); + exit; + } + // Prepare prompt $system_message = "You are a helpful IT documentation assistant. You will create a well-structured HTML template for IT documentation based on a given prompt. Include headings, subheadings, bullet points, and possibly tables for clarity. No Lorem Ipsum, use realistic placeholders and professional language."; $user_message = "Create an HTML formatted IT documentation template based on the following request:\n\n\"$prompt\"\n\nThe template should be structured, professional, and useful for IT staff. Include relevant sections, instructions, prerequisites, and best practices."; - $post_data = [ - "model" => "$model_name", - "messages" => [ - ["role" => "system", "content" => $system_message], - ["role" => "user", "content" => $user_message] - ], - "temperature" => 0.5 - ]; - - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_POST, true); - curl_setopt($ch, CURLOPT_HTTPHEADER, [ - 'Content-Type: application/json', - 'Authorization: Bearer ' . $key + $result = callAiApi($model, [ + ["role" => "system", "content" => $system_message], + ["role" => "user", "content" => $user_message] ]); - curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data)); - $response = curl_exec($ch); - if (curl_errno($ch)) { - echo "Error: " . curl_error($ch); + if (!$result['ok']) { + echo "

    " . escapeHtml($result['error']) . "

    "; exit; } - curl_close($ch); - - $response_data = json_decode($response, true); - $template = $response_data['choices'][0]['message']['content'] ?? "

    No content returned from AI.

    "; // Print the generated HTML template directly - echo $template; + echo $result['content']; } if (isset($_GET['ai_ticket_summary'])) { @@ -966,12 +927,12 @@ if (isset($_GET['ai_ticket_summary'])) { header('Content-Type: text/html; charset=UTF-8'); - $sql = mysqli_query($mysqli, "SELECT ai_model_name, ai_provider_api_key, ai_provider_api_url FROM ai_models LEFT JOIN ai_providers ON ai_model_ai_provider_id = ai_provider_id WHERE ai_model_use_case = 'General' LIMIT 1"); + $model = getAiModel('Tickets'); - $row = mysqli_fetch_assoc($sql); - $model_name = $row['ai_model_name']; - $url = $row['ai_provider_api_url']; - $key = $row['ai_provider_api_key']; + if (!$model) { + echo escapeHtml(aiModelMissingError('Tickets')); + exit; + } // Retrieve the ticket_id from POST $ticket_id = intval($_POST['ticket_id']); @@ -1048,38 +1009,17 @@ if (isset($_GET['ai_ticket_summary'])) { If any part of the ticket or replies is unclear or ambiguous, mention it in the summary and suggest if further clarification is needed. "; - // Prepare the POST data - $post_data = [ - "model" => "$model_name", - "messages" => [ - ["role" => "system", "content" => "Your task is to summarize IT support tickets with clear, concise details."], - ["role" => "user", "content" => $prompt] - ], - "temperature" => 0.3 - ]; - - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_POST, true); - curl_setopt($ch, CURLOPT_HTTPHEADER, [ - 'Content-Type: application/json', - 'Authorization: Bearer ' . $key + $result = callAiApi($model, [ + ["role" => "system", "content" => "Your task is to summarize IT support tickets with clear, concise details."], + ["role" => "user", "content" => $prompt] ]); - curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data)); - $response = curl_exec($ch); - if (curl_errno($ch)) { - echo "Error: " . curl_error($ch); + if (!$result['ok']) { + echo "

    " . escapeHtml($result['error']) . "

    "; exit; } - curl_close($ch); - $response_data = json_decode($response, true); - $summary = $response_data['choices'][0]['message']['content'] ?? "No summary available."; - - - echo $summary; // nl2br to convert newlines to
    , htmlspecialchars to prevent XSS + echo $result['content']; } // Stops people trying to use sub-domains in the domains tracker diff --git a/agent/post.php b/agent/post.php index 9c498ba67..810918239 100644 --- a/agent/post.php +++ b/agent/post.php @@ -10,8 +10,12 @@ require_once __DIR__ . "/../includes/check_login.php"; // Only allow running post files via inclusion (prevents people/bots poking them directly) define('FROM_POST_HANDLER', true); -// Load all agent module POST logic +// Load all agent module POST logic. // TODO: selectively load per-module like admin does, keyed off request path (not referer) +// *_model.php is a RESERVED suffix: those files are not handlers, they are inline +// field-parsing fragments that read $_POST at include time, so the glob must not +// pull them in. A handler named *_model.php is silently never loaded - name entity +// handlers around it (admin/post/ai_models.php, not ai_model.php). foreach (glob(__DIR__ . "/post/*.php") as $user_module) { if (!str_ends_with($user_module, '_model.php')) { require_once $user_module; @@ -21,3 +25,11 @@ foreach (glob(__DIR__ . "/post/*.php") as $user_module) { // Logout is shared between portals require_once __DIR__ . "/../post/logout.php"; require_once __DIR__ . "/../post/misc.php"; + +// Every handler above exits or redirects, so getting here means no handler claimed +// the request - a blank page and no trace of why. Log it; the usual cause is a +// handler file that never loaded. +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $unhandled = implode(', ', array_slice(array_keys($_POST), 0, 10)); + logApp('Request', 'warning', "Unhandled POST to agent/post.php - no handler matched. Fields: $unhandled"); +} diff --git a/db.sql b/db.sql index c0bcebd73..e039a630c 100644 --- a/db.sql +++ b/db.sql @@ -50,6 +50,7 @@ CREATE TABLE `ai_models` ( `ai_model_name` varchar(200) NOT NULL, `ai_model_prompt` text DEFAULT NULL, `ai_model_use_case` varchar(200) DEFAULT NULL, + `ai_model_temperature` decimal(3,2) DEFAULT NULL, `ai_model_created_at` datetime NOT NULL DEFAULT current_timestamp(), `ai_model_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(), `ai_model_ai_provider_id` int(11) NOT NULL, diff --git a/functions.php b/functions.php index ff70057de..fbea6e270 100644 --- a/functions.php +++ b/functions.php @@ -22,6 +22,7 @@ require_once __DIR__ . '/functions/logging.php'; require_once __DIR__ . '/functions/app.php'; require_once __DIR__ . '/functions/payments.php'; require_once __DIR__ . '/functions/sla.php'; +require_once __DIR__ . '/functions/ai.php'; require_once __DIR__ . '/functions/export.php'; require_once __DIR__ . '/functions/calendar.php'; require_once __DIR__ . '/functions/backup.php'; diff --git a/functions/ai.php b/functions/ai.php new file mode 100644 index 000000000..76e88e94f --- /dev/null +++ b/functions/ai.php @@ -0,0 +1,132 @@ + true, 'content' => '...'] + * ['ok' => false, 'error' => 'short message safe to show the user'] + * + * Provider detail - status code, error type, code and message - goes to the app log + * so a misconfiguration is diagnosable. The API key and the message bodies never do. + */ +function callAiApi($model, $messages) { + + $data = [ + 'model' => $model['ai_model_name'], + 'messages' => $messages, + ]; + + // Only send a temperature when the model has one configured. Newer OpenAI models + // accept nothing but their own default and 400 on anything else, which is what + // the old hardcoded 0.5 / 0.3 ran into. + if (isset($model['ai_model_temperature']) && $model['ai_model_temperature'] !== '') { + $data['temperature'] = floatval($model['ai_model_temperature']); + } + + $ch = curl_init($model['ai_provider_api_url']); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); + curl_setopt($ch, CURLOPT_TIMEOUT, AI_REQUEST_TIMEOUT); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Content-Type: application/json', + 'Authorization: Bearer ' . $model['ai_provider_api_key'], + ]); + + $response = curl_exec($ch); + $status = intval(curl_getinfo($ch, CURLINFO_RESPONSE_CODE)); + $transport_error = curl_error($ch); + curl_close($ch); + + // Enough to tell one provider/model pairing from another in the log + $context = $model['ai_provider_name'] . ' / ' . $model['ai_model_name']; + + if ($response === false) { + logApp('AI', 'error', "$context - could not reach the provider: $transport_error"); + return ['ok' => false, 'error' => 'Could not reach the AI provider.']; + } + + $decoded = json_decode($response, true); + + if ($status < 200 || $status > 299) { + $provider_error = $decoded['error'] ?? []; + $detail = "$context - HTTP $status"; + foreach (['type', 'code', 'param'] as $field) { + if (!empty($provider_error[$field])) { + $detail .= " $field=" . $provider_error[$field]; + } + } + if (!empty($provider_error['message'])) { + $detail .= ' - ' . $provider_error['message']; + } + logApp('AI', 'error', $detail); + return ['ok' => false, 'error' => 'The AI provider rejected the request - see Admin > App Logs.']; + } + + if (!isset($decoded['choices'][0]['message']['content'])) { + logApp('AI', 'error', "$context - HTTP $status but the response carried no choices[0].message.content"); + return ['ok' => false, 'error' => 'The AI provider returned an unexpected response - see Admin > App Logs.']; + } + + return ['ok' => true, 'content' => $decoded['choices'][0]['message']['content']]; +} + +/* + * What to say when nothing is configured for a use case. Logged as well as shown, + * because "no model" and "model rejected the request" look identical from the UI. + */ +function aiModelMissingError($use_case) { + logApp('AI', 'warning', "No AI model configured for use case '$use_case' and no General model to fall back on"); + return "No AI model is configured for $use_case. Add one under Admin > AI Models."; +} diff --git a/js/app.js b/js/app.js index 0b988a571..e1b08476e 100644 --- a/js/app.js +++ b/js/app.js @@ -145,13 +145,23 @@ $(document).ready(function() { return response.json(); }) .then(data => { - editor.undoManager.transact(function() { - editor.setContent(data.rewordedText || 'Error: Could not reword the text.'); - }); - editor.setProgressState(false); rewordButtonApi.setEnabled(true); + // Leave the user's text alone if the reword failed + if (data.error || !data.rewordedText) { + editor.notificationManager.open({ + text: data.error || 'Could not reword the text.', + type: 'error', + timeout: 8000 + }); + return; + } + + editor.undoManager.transact(function() { + editor.setContent(data.rewordedText); + }); + editor.notificationManager.open({ text: 'Text reworded successfully!', type: 'success', @@ -245,7 +255,7 @@ $(document).ready(function() { rewordButtonApi.setEnabled(false); editor.setProgressState(true); - fetch('ajax.php?ai_reword', { + fetch('ajax.php?ai_reword&use_case=Tickets', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: content }), @@ -255,11 +265,22 @@ $(document).ready(function() { return response.json(); }) .then(data => { - editor.undoManager.transact(function() { - editor.setContent(data.rewordedText || 'Error: Could not reword the text.'); - }); editor.setProgressState(false); rewordButtonApi.setEnabled(true); + + // Leave the user's text alone if the reword failed + if (data.error || !data.rewordedText) { + editor.notificationManager.open({ + text: data.error || 'Could not reword the text.', + type: 'error', + timeout: 8000 + }); + return; + } + + editor.undoManager.transact(function() { + editor.setContent(data.rewordedText); + }); editor.notificationManager.open({ text: 'Text reworded successfully!', type: 'success', From ac598f6379e5d96599fa24e33f4a6d3fdf8995de Mon Sep 17 00:00:00 2001 From: johnnyq Date: Thu, 6 Aug 2026 19:25:39 -0400 Subject: [PATCH 16/25] Fix system-generated ticket replies booking fake time worked --- CONTRIBUTING.md | 4 +- agent/post/task.php | 27 ++++-------- agent/post/ticket.php | 24 +++++------ scripts/audit_system_reply_time.sql | 64 +++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 32 deletions(-) create mode 100644 scripts/audit_system_reply_time.sql diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 668c56cc3..7ebf94f02 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -228,7 +228,9 @@ Per [SECURITY.md](SECURITY.md) — never in a public issue. --- ## Conventions - + +**Only technician-entered time is time worked.** `ticket_replies.ticket_reply_time_worked` is billable labour and feeds ticket totals, the technician and client time reports, project totals, invoicing and the API. A reply the *system* writes — assignment, priority change, merge, close, invoice/quote created, schedule edited, task completed or reopened — is an audit trail, not work, and records `'00:00:00'`. Only a value the technician actually typed goes in that column. Task completion estimates are planning information and stay on the task; they are never converted into time worked. `agent/ticket.php` hides the clock badge on a reply whose time is exactly `00:00:00`, so a zero renders as no time rather than as "0m". + **Database naming.** Every column is prefixed with the singular name of the entity it belongs to: `tickets.ticket_id`, `tickets.ticket_subject`, `clients.client_name`. This makes JOIN results unambiguous, so a `SELECT *` across joins is never *wrong*. New tables must follow it. **Select the columns you use, not `*`.** Unambiguous is not the same as cheap. `SELECT *` across three joined tables fetches every column of all three, including the `*_notes` and `*_details` TEXT columns, and throws away whatever the page never renders. A search result list that shows five fields was pulling sixty. List the columns instead: diff --git a/agent/post/task.php b/agent/post/task.php index cb49fac26..ab7d1f45e 100644 --- a/agent/post/task.php +++ b/agent/post/task.php @@ -113,23 +113,18 @@ if (isset($_GET['complete_task'])) { $task_id = intval($_GET['complete_task']); // Get Client ID - $sql = mysqli_query($mysqli, "SELECT task_completion_estimate, task_name, ticket_client_id, ticket_id FROM tasks LEFT JOIN tickets ON ticket_id = task_ticket_id WHERE task_id = $task_id"); + $sql = mysqli_query($mysqli, "SELECT task_name, ticket_client_id, ticket_id FROM tasks LEFT JOIN tickets ON ticket_id = task_ticket_id WHERE task_id = $task_id"); $row = mysqli_fetch_assoc($sql); $client_id = intval($row['ticket_client_id']); enforceClientAccess(); $task_name = escapeSql($row['task_name']); - $task_completion_estimate = intval($row['task_completion_estimate']); $ticket_id = intval($row['ticket_id']); mysqli_query($mysqli, "UPDATE tasks SET task_completed_at = NOW(), task_completed_by = $session_user_id WHERE task_id = $task_id"); - // Convert task completion estimate from minutes to TIME format - $time_worked = gmdate("H:i:s", $task_completion_estimate * 60); // Convert minutes to HH:MM:SS - - // Add reply - mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Completed Task - $task_name', ticket_reply_time_worked = '$time_worked', ticket_reply_type = 'Internal', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); - - $ticket_reply_id = mysqli_insert_id($mysqli); + // Audit trail only - task_completion_estimate is planning information, not labour. + // Booking it as time worked double-counted against whatever the tech actually logged. + mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Completed Task - $task_name', ticket_reply_time_worked = '00:00:00', ticket_reply_type = 'Internal', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); logAudit("Task", "Edit", "$session_name completed task $task_name", $client_id, $task_id); @@ -157,10 +152,8 @@ if (isset($_GET['undo_complete_task'])) { mysqli_query($mysqli, "UPDATE tasks SET task_completed_at = NULL, task_completed_by = NULL WHERE task_id = $task_id"); - // Add reply - mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Undo Completed Task - $task_name', ticket_reply_time_worked = '00:01:00', ticket_reply_type = 'Internal', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); - - $ticket_reply_id = mysqli_insert_id($mysqli); + // Audit trail only - see complete_task + mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Undo Completed Task - $task_name', ticket_reply_time_worked = '00:00:00', ticket_reply_type = 'Internal', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); logAudit("Task", "Edit", "$session_name marked task $task_name as incomplete", $client_id, $task_id); @@ -431,9 +424,7 @@ if (isset($_GET['complete_all_tasks'])) { mysqli_query($mysqli, "UPDATE tasks SET task_completed_at = NOW(), task_completed_by = $session_user_id WHERE task_ticket_id = $ticket_id AND task_completed_at IS NULL"); // Add reply - mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Marked all tasks complete', ticket_reply_type = 'Internal', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); - - $ticket_reply_id = mysqli_insert_id($mysqli); + mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Marked all tasks complete', ticket_reply_time_worked = '00:00:00', ticket_reply_type = 'Internal', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); logAudit("Ticket", "Edit", "$session_name marked all tasks complete for ticket", $client_id, $ticket_id); @@ -458,9 +449,7 @@ if (isset($_GET['undo_complete_all_tasks'])) { mysqli_query($mysqli, "UPDATE tasks SET task_completed_at = NULL, task_completed_by = NULL WHERE task_ticket_id = $ticket_id AND task_completed_at IS NOT NULL"); // Add reply - mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Marked all tasks incomplete', ticket_reply_type = 'Internal', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); - - $ticket_reply_id = mysqli_insert_id($mysqli); + mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Marked all tasks incomplete', ticket_reply_time_worked = '00:00:00', ticket_reply_type = 'Internal', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); logAudit("Ticket", "Edit", "$session_name marked all tasks as incomplete for ticket", $client_id, $ticket_id); diff --git a/agent/post/ticket.php b/agent/post/ticket.php index aa6bfb224..8950349c1 100644 --- a/agent/post/ticket.php +++ b/agent/post/ticket.php @@ -892,7 +892,7 @@ if (isset($_POST['assign_ticket'])) { mysqli_query($mysqli, "UPDATE tickets SET ticket_assigned_to = $assigned_to, ticket_status = '$ticket_status' WHERE ticket_id = $ticket_id"); syncTicketSlaClock($ticket_id); - mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = '$ticket_reply', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:01:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); + mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = '$ticket_reply', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:00:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); logTicketHistory($ticket_id, "$session_name assigned the ticket to $agent_name"); @@ -1101,7 +1101,7 @@ if (isset($_POST['bulk_assign_ticket'])) { mysqli_query($mysqli, "UPDATE tickets SET ticket_assigned_to = $assign_to, ticket_status = $ticket_status WHERE ticket_id = $ticket_id"); syncTicketSlaClock($ticket_id); - mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = '$ticket_reply', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:01:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); + mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = '$ticket_reply', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:00:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); logTicketHistory($ticket_id, "$session_name assigned the ticket to $agent_name"); @@ -1188,7 +1188,7 @@ if (isset($_POST['bulk_edit_ticket_priority'])) { mysqli_query($mysqli, "UPDATE tickets SET ticket_priority = '$priority' WHERE ticket_id = $ticket_id"); applyTicketSla($ticket_id); - mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = '$session_name updated the priority from $current_ticket_priority to $priority', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:01:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); + mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = '$session_name updated the priority from $current_ticket_priority to $priority', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:00:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); logAudit("Ticket", "Edit", "$session_name updated the priority on ticket $ticket_prefix$ticket_number - $ticket_subject from $original_ticket_priority to $priority", $client_id, $ticket_id); @@ -1307,13 +1307,13 @@ if (isset($_POST['bulk_merge_tickets'])) { if (empty($ticket_first_response_at)) { setTicketFirstResponse($ticket_id); } - mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Ticket $ticket_prefix$ticket_number bulk merged into
    $ticket_prefix$merge_into_ticket_number. Comment: $merge_comment', ticket_reply_time_worked = '00:01:00', ticket_reply_type = '$ticket_reply_type', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); + mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Ticket $ticket_prefix$ticket_number bulk merged into $ticket_prefix$merge_into_ticket_number. Comment: $merge_comment', ticket_reply_time_worked = '00:00:00', ticket_reply_type = '$ticket_reply_type', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); mysqli_query($mysqli, "UPDATE tickets SET ticket_status = '5', ticket_resolved_at = NOW(), ticket_closed_at = NOW(), ticket_closed_by = $session_user_id WHERE ticket_id = $ticket_id") or die(mysqli_error($mysqli)); syncTicketSlaClock($ticket_id); setTicketResolutionSlaMet($ticket_id); // Update new parent ticket - mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Ticket $ticket_prefix$ticket_number was bulk merged into this ticket with comment: $merge_comment.

    $ticket_subject
    $ticket_details', ticket_reply_time_worked = '00:01:00', ticket_reply_type = 'Internal', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $merge_into_ticket_id"); + mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Ticket $ticket_prefix$ticket_number was bulk merged into this ticket with comment: $merge_comment.

    $ticket_subject
    $ticket_details', ticket_reply_time_worked = '00:00:00', ticket_reply_type = 'Internal', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $merge_into_ticket_id"); logTicketHistory($ticket_id, "$session_name merged this ticket into $ticket_prefix$merge_into_ticket_number and closed it"); @@ -2240,14 +2240,14 @@ if (isset($_POST['merge_ticket'])) { setTicketFirstResponse($ticket_id); } - mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Ticket $ticket_prefix$ticket_number merged into $ticket_prefix$merge_into_ticket_number. Comment: $merge_comment', ticket_reply_time_worked = '00:01:00', ticket_reply_type = '$ticket_reply_type', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); + mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Ticket $ticket_prefix$ticket_number merged into $ticket_prefix$merge_into_ticket_number. Comment: $merge_comment', ticket_reply_time_worked = '00:00:00', ticket_reply_type = '$ticket_reply_type', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); mysqli_query($mysqli, "UPDATE tickets SET ticket_status = '5', ticket_resolved_at = NOW(), ticket_closed_at = NOW(), ticket_closed_by = $session_user_id WHERE ticket_id = $ticket_id") or die(mysqli_error($mysqli)); syncTicketSlaClock($ticket_id); setTicketResolutionSlaMet($ticket_id); //Update new parent ticket - mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Ticket $ticket_prefix$ticket_number was merged into this ticket with comment: $merge_comment.

    $ticket_subject
    $ticket_details', ticket_reply_time_worked = '00:01:00', ticket_reply_type = '$ticket_reply_type', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $merge_into_ticket_id"); + mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Ticket $ticket_prefix$ticket_number was merged into this ticket with comment: $merge_comment.

    $ticket_subject
    $ticket_details', ticket_reply_time_worked = '00:00:00', ticket_reply_type = '$ticket_reply_type', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $merge_into_ticket_id"); mysqli_query($mysqli, "UPDATE tickets SET ticket_updated_at = NOW() WHERE ticket_id = $merge_into_ticket_id"); @@ -2428,7 +2428,7 @@ if (isset($_GET['close_ticket'])) { syncTicketSlaClock($ticket_id); setTicketResolutionSlaMet($ticket_id); - mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Ticket closed.', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:01:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); + mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Ticket closed.', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:00:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); logTicketHistory($ticket_id, "$session_name closed the ticket"); @@ -2654,7 +2654,7 @@ if (isset($_POST['add_invoice_from_ticket'])) { mysqli_query($mysqli, "INSERT INTO history SET history_status = 'Draft', history_description = 'Invoice created from Ticket $ticket_prefix$ticket_number', history_invoice_id = $invoice_id"); // Add internal note to ticket, and link to invoice in database - mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Created invoice $config_invoice_prefix$invoice_number for this ticket.', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:01:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); + mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Created invoice $config_invoice_prefix$invoice_number for this ticket.', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:00:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); mysqli_query($mysqli, "UPDATE tickets SET ticket_invoice_id = $invoice_id WHERE ticket_id = $ticket_id"); @@ -2727,7 +2727,7 @@ if (isset($_POST['add_quote_from_ticket'])) { mysqli_query($mysqli, "INSERT INTO quote_items SET item_name = '$item_name', item_description = '$item_description', item_quantity = $qty, item_price = $price, item_subtotal = $subtotal, item_tax = $tax_amount, item_total = $total, item_order = 1, item_tax_id = $tax_id, item_quote_id = $quote_id"); // Add internal note to ticket, and link to invoice in database - mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Created quote $config_quote_prefix$quote_number for this ticket.', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:01:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); + mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Created quote $config_quote_prefix$quote_number for this ticket.', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:00:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); mysqli_query($mysqli, "UPDATE tickets SET ticket_quote_id = $quote_id WHERE ticket_id = $ticket_id LIMIT 1"); // Logging + redirects @@ -3133,7 +3133,7 @@ if (isset($_POST['edit_ticket_schedule'])) { // Update ticket reply $ticket_reply_note = "Ticket scheduled for $email_datetime " . (boolval($onsite) ? '(onsite).' : '(remote).'); - mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = '$ticket_reply_note', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:01:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); + mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = '$ticket_reply_note', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:00:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); logAudit("Ticket", "Edit", "$session_name edited ticket schedule", $client_id, $ticket_id); @@ -3298,7 +3298,7 @@ if (isset($_GET['cancel_ticket_schedule'])) { // Update ticket reply $ticket_reply_note = "Ticket schedule cancelled."; - mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = '$ticket_reply_note', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:01:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); + mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = '$ticket_reply_note', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:00:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); logAudit("Ticket", "Edit", "$session_name cancelled ticket schedule", $client_id, $ticket_id); diff --git a/scripts/audit_system_reply_time.sql b/scripts/audit_system_reply_time.sql new file mode 100644 index 000000000..9757f07b6 --- /dev/null +++ b/scripts/audit_system_reply_time.sql @@ -0,0 +1,64 @@ +-- ITFlow - how much billable time did system-generated replies invent? +-- +-- Run these BEFORE deciding whether to correct historical data. Nothing here +-- writes; the UPDATE at the bottom is commented out on purpose. +-- +-- Background: until this fix, replies ITFlow wrote itself booked time worked - +-- one minute for assignment / priority / merge / close / invoice / quote / +-- schedule / task reopen, and the task's full completion estimate for task +-- completion. That time is in ticket totals, technician and client time +-- reports, project totals and anything already invoiced. + +-- 1. Total invented time, by reply kind. +SELECT + CASE + WHEN ticket_reply LIKE 'Completed Task - %' THEN 'Task completed (estimate booked)' + WHEN ticket_reply LIKE 'Undo Completed Task - %' THEN 'Task reopened' + WHEN ticket_reply LIKE 'Ticket closed.' THEN 'Ticket closed' + WHEN ticket_reply LIKE 'Created invoice %' THEN 'Invoice created' + WHEN ticket_reply LIKE 'Created quote %' THEN 'Quote created' + WHEN ticket_reply LIKE 'Ticket %merged into%' THEN 'Merged' + WHEN ticket_reply LIKE '%updated the priority from%' THEN 'Priority changed' + ELSE 'Other' + END AS reply_kind, + COUNT(*) AS replies, + SEC_TO_TIME(SUM(TIME_TO_SEC(ticket_reply_time_worked))) AS total_time +FROM ticket_replies +WHERE ticket_reply_type = 'Internal' + AND ticket_reply_archived_at IS NULL + AND TIME_TO_SEC(ticket_reply_time_worked) > 0 + AND ( + ticket_reply LIKE 'Completed Task - %' + OR ticket_reply LIKE 'Undo Completed Task - %' + OR ticket_reply = 'Ticket closed.' + OR ticket_reply LIKE 'Created invoice %' + OR ticket_reply LIKE 'Created quote %' + OR ticket_reply LIKE 'Ticket %merged into%' + OR ticket_reply LIKE '%updated the priority from%' + ) +GROUP BY reply_kind +ORDER BY SUM(TIME_TO_SEC(ticket_reply_time_worked)) DESC; + +-- 2. The same rows per client, so you can see whose totals moved. +SELECT client_name, + COUNT(*) AS replies, + SEC_TO_TIME(SUM(TIME_TO_SEC(ticket_reply_time_worked))) AS total_time +FROM ticket_replies +LEFT JOIN tickets ON ticket_id = ticket_reply_ticket_id +LEFT JOIN clients ON client_id = ticket_client_id +WHERE ticket_reply_type = 'Internal' + AND ticket_reply_archived_at IS NULL + AND TIME_TO_SEC(ticket_reply_time_worked) > 0 + AND (ticket_reply LIKE 'Completed Task - %' OR ticket_reply LIKE 'Undo Completed Task - %') +GROUP BY client_name +ORDER BY SUM(TIME_TO_SEC(ticket_reply_time_worked)) DESC; + +-- 3. Correction, if you want it. NOT shipped as a migration: these rows are +-- editable in the UI, so some of them may carry time a technician put there +-- deliberately, and anything already invoiced should not move underneath the +-- invoice. Review the output above first, back up, then run by hand. +-- +-- UPDATE ticket_replies +-- SET ticket_reply_time_worked = '00:00:00' +-- WHERE ticket_reply_type = 'Internal' +-- AND (ticket_reply LIKE 'Completed Task - %' OR ticket_reply LIKE 'Undo Completed Task - %'); From 10f0c9de58824370a5ff5e5616414a4a1672d4e5 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Thu, 6 Aug 2026 19:26:43 -0400 Subject: [PATCH 17/25] remove audit system time script --- scripts/audit_system_reply_time.sql | 64 ----------------------------- 1 file changed, 64 deletions(-) delete mode 100644 scripts/audit_system_reply_time.sql diff --git a/scripts/audit_system_reply_time.sql b/scripts/audit_system_reply_time.sql deleted file mode 100644 index 9757f07b6..000000000 --- a/scripts/audit_system_reply_time.sql +++ /dev/null @@ -1,64 +0,0 @@ --- ITFlow - how much billable time did system-generated replies invent? --- --- Run these BEFORE deciding whether to correct historical data. Nothing here --- writes; the UPDATE at the bottom is commented out on purpose. --- --- Background: until this fix, replies ITFlow wrote itself booked time worked - --- one minute for assignment / priority / merge / close / invoice / quote / --- schedule / task reopen, and the task's full completion estimate for task --- completion. That time is in ticket totals, technician and client time --- reports, project totals and anything already invoiced. - --- 1. Total invented time, by reply kind. -SELECT - CASE - WHEN ticket_reply LIKE 'Completed Task - %' THEN 'Task completed (estimate booked)' - WHEN ticket_reply LIKE 'Undo Completed Task - %' THEN 'Task reopened' - WHEN ticket_reply LIKE 'Ticket closed.' THEN 'Ticket closed' - WHEN ticket_reply LIKE 'Created invoice %' THEN 'Invoice created' - WHEN ticket_reply LIKE 'Created quote %' THEN 'Quote created' - WHEN ticket_reply LIKE 'Ticket %merged into%' THEN 'Merged' - WHEN ticket_reply LIKE '%updated the priority from%' THEN 'Priority changed' - ELSE 'Other' - END AS reply_kind, - COUNT(*) AS replies, - SEC_TO_TIME(SUM(TIME_TO_SEC(ticket_reply_time_worked))) AS total_time -FROM ticket_replies -WHERE ticket_reply_type = 'Internal' - AND ticket_reply_archived_at IS NULL - AND TIME_TO_SEC(ticket_reply_time_worked) > 0 - AND ( - ticket_reply LIKE 'Completed Task - %' - OR ticket_reply LIKE 'Undo Completed Task - %' - OR ticket_reply = 'Ticket closed.' - OR ticket_reply LIKE 'Created invoice %' - OR ticket_reply LIKE 'Created quote %' - OR ticket_reply LIKE 'Ticket %merged into%' - OR ticket_reply LIKE '%updated the priority from%' - ) -GROUP BY reply_kind -ORDER BY SUM(TIME_TO_SEC(ticket_reply_time_worked)) DESC; - --- 2. The same rows per client, so you can see whose totals moved. -SELECT client_name, - COUNT(*) AS replies, - SEC_TO_TIME(SUM(TIME_TO_SEC(ticket_reply_time_worked))) AS total_time -FROM ticket_replies -LEFT JOIN tickets ON ticket_id = ticket_reply_ticket_id -LEFT JOIN clients ON client_id = ticket_client_id -WHERE ticket_reply_type = 'Internal' - AND ticket_reply_archived_at IS NULL - AND TIME_TO_SEC(ticket_reply_time_worked) > 0 - AND (ticket_reply LIKE 'Completed Task - %' OR ticket_reply LIKE 'Undo Completed Task - %') -GROUP BY client_name -ORDER BY SUM(TIME_TO_SEC(ticket_reply_time_worked)) DESC; - --- 3. Correction, if you want it. NOT shipped as a migration: these rows are --- editable in the UI, so some of them may carry time a technician put there --- deliberately, and anything already invoiced should not move underneath the --- invoice. Review the output above first, back up, then run by hand. --- --- UPDATE ticket_replies --- SET ticket_reply_time_worked = '00:00:00' --- WHERE ticket_reply_type = 'Internal' --- AND (ticket_reply LIKE 'Completed Task - %' OR ticket_reply LIKE 'Undo Completed Task - %'); From db96766ab00904c4ebccbb322333c9b6f3ed155d Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 7 Aug 2026 12:44:56 -0400 Subject: [PATCH 18/25] Fix Error on Scheduling Tickets, Fixed Zapcal Path --- functions/app.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/functions/app.php b/functions/app.php index 9a6626df8..c285e976b 100644 --- a/functions/app.php +++ b/functions/app.php @@ -416,7 +416,7 @@ function addToMailQueue($data) { } function createiCalStr($datetime, $title, $description, $location) { - require_once "libs/zapcal/zapcallib.php"; + require_once "../libs/zapcal/zapcallib.php"; // Create the iCal object $cal_event = new ZCiCal(); @@ -443,7 +443,7 @@ function createiCalStr($datetime, $title, $description, $location) { } function createiCalStrCancel($originaliCalStr) { - require_once "libs/zapcal/zapcallib.php"; + require_once "../libs/zapcal/zapcallib.php"; // Import the original iCal string $cal_event = new ZCiCal($originaliCalStr); From 656aa95a4eb44d86854ed0aed2a47518bcca12fa Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 7 Aug 2026 18:09:01 -0400 Subject: [PATCH 19/25] Fix WebUI setup regression locking out after first step --- setup/index.php | 137 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 119 insertions(+), 18 deletions(-) diff --git a/setup/index.php b/setup/index.php index f8f2e8aef..72d4f8dad 100644 --- a/setup/index.php +++ b/setup/index.php @@ -15,22 +15,25 @@ $can_show_restore = false; $should_skip_to_user = false; /* - * An install with users in it is a live install, and setup is closed on one whatever - * config.php says. + * How far through the wizard this install already is. Each step is a separate question + * because each one guards a different handler below - answering all of them with "are there + * users?" is what used to lock the wizard out three steps early. * - * This used to default $config_enable_setup to 1 when the flag was absent, which fails the - * wrong way: config.php is written when the database step completes but the flag is only - * appended at the very end of a successful run, so an install abandoned in between - or one - * where that final append failed - left the restore below reachable with no authentication - * at all. That endpoint drops every table and imports whatever archive it is handed, and it - * rewrites the uploads directory, including the .htaccess that stops PHP running there. + * $install_is_live - users exist. A restore would destroy real data, so restore closes + * and points at the CLI. One user row is enough. + * $company_exists - the company step has run (companies row, and settings seeded). + * $localization_done - the localization step has run (company_locale filled in). */ $install_is_live = false; +$company_exists = false; +$localization_done = false; +$resume_step = 'checks'; if (file_exists("../config.php") && $mysqli_available) { $table_result = mysqli_query($mysqli, "SHOW TABLES LIKE 'users'"); if ($table_result && mysqli_num_rows($table_result) > 0) { $should_skip_to_user = true; + $resume_step = 'user'; $user_count_result = mysqli_query($mysqli, "SELECT COUNT(*) AS user_count FROM users"); if ($user_count_result) { @@ -44,6 +47,26 @@ if (file_exists("../config.php") && $mysqli_available) { } } + if ($install_is_live) { + $resume_step = 'company'; + + $company_result = mysqli_query($mysqli, "SELECT company_locale FROM companies WHERE company_id = 1"); + if (!$company_result) { + // Cannot prove either step is outstanding, so treat both as done + $company_exists = true; + $localization_done = true; + $resume_step = 'telemetry'; + } elseif ($company_row = mysqli_fetch_assoc($company_result)) { + $company_exists = true; + $resume_step = 'localization'; + + if (trim($company_row['company_locale'] ?? '') !== '') { + $localization_done = true; + $resume_step = 'telemetry'; + } + } + } + // Restore needs a database connection and an empty install. A populated one restores // from the command line instead - scripts/restore_cli.php. if (!$install_is_live) { @@ -54,11 +77,27 @@ if (file_exists("../config.php") && $mysqli_available) { } } +/* + * config.php is written when the database step completes, but $config_enable_setup is only + * appended to it by the LAST step, so the flag is absent for the whole middle of an install + * and the wizard has to stay open across that gap or it cannot be finished. + * + * Deriving the flag from the database instead - closing setup as soon as the install looked + * "live" - is what stranded people: the first user made it live, three steps before there + * were companies or settings rows, and /setup and /login.php then redirected at each other + * until the browser gave up. Deriving it from any later step has the same shape, because the + * step that writes the flag is behind the gate that reads it. + * + * So the page stays open until the flag says otherwise, and each handler below refuses to run + * a second time on its own. That keeps the reason the derived flag was added in the first + * place - the restore handler drops every table, imports whatever archive it is handed and + * rewrites the uploads directory - without the page-level gate that came with it. + */ if (!isset($config_enable_setup)) { - $config_enable_setup = $install_is_live ? 0 : 1; + $config_enable_setup = 1; } -if ($config_enable_setup == 0 || $install_is_live) { +if ($config_enable_setup == 0) { header("Location: /login.php"); exit; } @@ -246,8 +285,12 @@ if (isset($_POST['restore'])) { } if (isset($_POST['add_user'])) { - $user_count = mysqli_num_rows(mysqli_query($mysqli,"SELECT COUNT(*) FROM users")); - if ($user_count < 0) { + + // SELECT COUNT(*) returns exactly one row whatever the count is, so the mysqli_num_rows() + // test this replaces was always 1 and never fired: a resubmitted form created a second + // user and then died on the duplicate user_settings row. $install_is_live is the same + // count, taken at the top of the file, and it fails closed. + if ($install_is_live) { $_SESSION['alert_message'] = "Users already exist in the database. Clear them to reconfigure here."; header("Location: ?company"); exit; @@ -265,7 +308,10 @@ if (isset($_POST['add_user'])) { mysqli_query($mysqli,"INSERT INTO users SET user_name = '$name', user_email = '$email', user_password = '$password', user_specific_encryption_ciphertext = '$user_specific_encryption_ciphertext', user_role_id = 3"); - mkdirMissing("../uploads/users/1"); + // Normally 1, but the table's AUTO_INCREMENT can already have moved on, so ask for it. + $user_id = intval(mysqli_insert_id($mysqli)); + + mkdirMissing("../uploads/users/$user_id"); //Check to see if a file is attached if ($_FILES['file']['tmp_name'] != '') { @@ -295,13 +341,13 @@ if (isset($_POST['add_user'])) { if ($file_error == 0) { // directory in which the uploaded file will be moved - $upload_file_dir = "../uploads/users/1/"; + $upload_file_dir = "../uploads/users/$user_id/"; $dest_path = $upload_file_dir . $new_file_name; move_uploaded_file($file_tmp_path, $dest_path); //Set Avatar - mysqli_query($mysqli,"UPDATE users SET user_avatar = '$new_file_name' WHERE user_id = 1"); + mysqli_query($mysqli,"UPDATE users SET user_avatar = '$new_file_name' WHERE user_id = $user_id"); $_SESSION['alert_message'] = 'File successfully uploaded.'; } else { @@ -311,7 +357,7 @@ if (isset($_POST['add_user'])) { } //Create Settings - mysqli_query($mysqli,"INSERT INTO user_settings SET user_id = 1"); + mysqli_query($mysqli,"INSERT INTO user_settings SET user_id = $user_id"); $_SESSION['alert_message'] = "User $name created"; @@ -322,6 +368,13 @@ if (isset($_POST['add_user'])) { if (isset($_POST['add_company_settings'])) { + // Run once. A second pass would add a second companies row and re-seed the defaults. + if ($company_exists) { + $_SESSION['alert_message'] = "Company details have already been saved."; + header("Location: ?localization"); + exit; + } + $name = escapeSql($_POST['name']); $country = escapeSql($_POST['country']); $address = escapeSql($_POST['address']); @@ -388,6 +441,13 @@ if (isset($_POST['add_company_settings'])) { if (isset($_POST['add_localization_settings'])) { + // Run once. A second pass would add a second Cash account. + if ($localization_done) { + $_SESSION['alert_message'] = "Localization has already been saved."; + header("Location: ?telemetry"); + exit; + } + $locale = escapeSql($_POST['locale']); $currency_code = escapeSql($_POST['currency_code']); $timezone = escapeSql($_POST['timezone']); @@ -1048,6 +1108,14 @@ if (isset($_POST['add_telemetry'])) {
    + + +

    This install already has a user - the rest of your team is added from Admin > Users once you are logged in.

    +
    + Continue Setup + + +
    @@ -1091,6 +1159,9 @@ if (isset($_POST['add_telemetry'])) { + + +
    @@ -1101,6 +1172,14 @@ if (isset($_POST['add_telemetry'])) {

    Step 4 - Company Details

    + + + +

    Company details have already been saved - they can be changed later from Admin > Settings.

    +
    + Continue Setup + +
    @@ -1220,6 +1299,9 @@ if (isset($_POST['add_telemetry'])) { + + +
    @@ -1230,6 +1312,14 @@ if (isset($_POST['add_telemetry'])) {

    Step 5 - Region and Language

    + + + +

    Localization has already been saved - it can be changed later from Admin > Settings.

    +
    + Continue Setup + +
    @@ -1284,6 +1374,9 @@ if (isset($_POST['add_telemetry'])) { + + +
    @@ -1356,7 +1449,11 @@ if (isset($_POST['add_telemetry'])) {
  • Don't hesitate to reach out on the forums if you need any assistance
  • Apache/PHP Error log:
  • -

    A database must be created before proceeding - click on the button below to get started.

    + +

    This install was left part-way through setup - click on the button below to pick up where it stopped.

    + +

    A database must be created before proceeding - click on the button below to get started.

    +

    ITFlow is free software: you can redistribute and/or modify it under the terms of the GNU General Public License.
    It is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.


    - + + + Continue Setup + + Create First User From d484629ebc464180ae23e05decba73e7bea4d518 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 8 Aug 2026 12:41:34 -0400 Subject: [PATCH 20/25] do not update ticket status in history if it is the same --- agent/post/ticket.php | 37 +++++++++++++++++++++++--------- api/v1/ticket_replies/create.php | 13 +++++++---- client/post.php | 9 +++++++- cron/ticket_email_parser.php | 5 ++++- 4 files changed, 48 insertions(+), 16 deletions(-) diff --git a/agent/post/ticket.php b/agent/post/ticket.php index 8950349c1..a8d9b85a7 100644 --- a/agent/post/ticket.php +++ b/agent/post/ticket.php @@ -1510,7 +1510,7 @@ if (isset($_POST['bulk_ticket_reply'])) { foreach ($_POST['ticket_ids'] as $ticket_id) { $ticket_id = intval($ticket_id); - $sql = mysqli_query($mysqli, "SELECT ticket_client_id, ticket_first_response_at, ticket_number, ticket_prefix, ticket_priority, + $sql = mysqli_query($mysqli, "SELECT ticket_client_id, ticket_status, ticket_first_response_at, ticket_number, ticket_prefix, ticket_priority, ticket_subject, ticket_url_key FROM tickets WHERE ticket_id = $ticket_id"); $row = mysqli_fetch_assoc($sql); @@ -1521,6 +1521,7 @@ if (isset($_POST['bulk_ticket_reply'])) { $url_key = escapeSql($row['ticket_url_key']); $ticket_first_response_at = escapeSql($row['ticket_first_response_at']); $client_id = intval($row['ticket_client_id']); + $original_ticket_status = intval($row['ticket_status']); // Don't Enforce Client Access if Ticket doesn't have an assigned client if ($client_id) { @@ -1547,8 +1548,12 @@ if (isset($_POST['bulk_ticket_reply'])) { mysqli_query($mysqli, "UPDATE tickets SET ticket_status = '$ticket_status' WHERE ticket_id = $ticket_id"); syncTicketSlaClock($ticket_id); - $new_status_name = escapeSql(getTicketStatusName($ticket_status)); - logTicketHistory($ticket_id, "$session_name set the status to $new_status_name"); + // Only record a status change when the status actually changed - Resolved + // is left out because the resolve block below logs it + if ($ticket_status !== $original_ticket_status && $ticket_status != 4) { + $new_status_name = escapeSql(getTicketStatusName($ticket_status)); + logTicketHistory($ticket_id, "$session_name set the status to $new_status_name"); + } logAudit("Ticket", "Reply", "$session_name replied to ticket $ticket_prefix$ticket_number - $ticket_subject and was a $ticket_reply_type reply", $client_id, $ticket_id); @@ -1559,8 +1564,9 @@ if (isset($_POST['bulk_ticket_reply'])) { triggerCustomAction('reply_reply_agent_public', $ticket_id); } - // Resolve the ticket, if set - if ($ticket_status == 4) { + // Resolve the ticket, if it is actually moving into Resolved - a bulk reply + // on an already-resolved ticket must not restamp resolved_at + if ($ticket_status == 4 && $original_ticket_status != 4) { mysqli_query($mysqli, "UPDATE tickets SET ticket_resolved_at = NOW() WHERE ticket_id = $ticket_id"); setTicketResolutionSlaMet($ticket_id); @@ -1834,7 +1840,10 @@ if (isset($_POST['add_ticket_reply'])) { $ticket_reply = $_POST['ticket_reply']; // Reply is SQL escaped below $ticket_status = intval($_POST['status']); - $client_id = intval(getFieldById('tickets', $ticket_id, 'ticket_client_id')); + // Read the ticket as it stands before the reply changes anything + $original_row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT ticket_client_id, ticket_status FROM tickets WHERE ticket_id = $ticket_id")); + $client_id = intval($original_row['ticket_client_id'] ?? 0); + $original_ticket_status = intval($original_row['ticket_status'] ?? 0); // Don't Enforce Client Access if Ticket doesn't have an assigned client if ($client_id) { @@ -1869,8 +1878,9 @@ if (isset($_POST['add_ticket_reply'])) { mysqli_query($mysqli, "UPDATE tickets SET ticket_status = $ticket_status, ticket_updated_at = NOW() WHERE ticket_id = $ticket_id"); syncTicketSlaClock($ticket_id); - // Resolve the ticket, if set - if ($ticket_status == 4) { + // Resolve the ticket, if it is actually moving into Resolved - replying on an + // already-resolved ticket must not restamp resolved_at or re-log the resolve + if ($ticket_status == 4 && $original_ticket_status != 4) { mysqli_query($mysqli, "UPDATE tickets SET ticket_resolved_at = NOW() WHERE ticket_id = $ticket_id"); setTicketResolutionSlaMet($ticket_id); @@ -2030,8 +2040,15 @@ if (isset($_POST['add_ticket_reply'])) { flashAlert("Stored on the ticket but too large to email: " . implode(', ', $skipped_names) . "", 'error'); } - $new_status_name = escapeSql(getTicketStatusName($ticket_status)); - logTicketHistory($ticket_id, "$session_name set the status to $new_status_name"); + /* + * The reply form preselects the ticket's current status, so most replies post + * it straight back - only record a status change when it actually changed. + * Resolved is left out because the resolve block above already logged it + */ + if ($ticket_status !== $original_ticket_status && $ticket_status != 4) { + $new_status_name = escapeSql(getTicketStatusName($ticket_status)); + logTicketHistory($ticket_id, "$session_name set the status to $new_status_name"); + } logAudit("Ticket", "Reply", "$session_name replied to ticket $ticket_prefix$ticket_number - $ticket_subject and was a $ticket_reply_type reply", $client_id, $ticket_id); diff --git a/api/v1/ticket_replies/create.php b/api/v1/ticket_replies/create.php index 009443acf..27a9b5e96 100644 --- a/api/v1/ticket_replies/create.php +++ b/api/v1/ticket_replies/create.php @@ -70,6 +70,7 @@ if (!empty($ticket_id) && !empty($reply)) { $ticket_url_key = escapeSql($ticket_row['ticket_url_key']); $ticket_first_response_at = escapeSql($ticket_row['ticket_first_response_at']); $client_id = intval($ticket_row['ticket_client_id']); + $original_ticket_status = intval($ticket_row['ticket_status']); // Mark first response time if required - internal notes don't count as a response if (empty($ticket_first_response_at) && $reply_type == 'Public') { @@ -87,11 +88,15 @@ if (!empty($ticket_id) && !empty($reply)) { if (!empty($reply_ticket_status)) { mysqli_query($mysqli, "UPDATE tickets SET ticket_status = $reply_ticket_status WHERE ticket_id = $ticket_id LIMIT 1"); - $new_status_name = escapeSql(getTicketStatusName($reply_ticket_status)); - logTicketHistory($ticket_id, "Status set to $new_status_name via the API ($api_key_name)"); + // Only record a status change when the status actually changed - + // Resolved is left out because the resolve block below logs it + if ($reply_ticket_status !== $original_ticket_status && $reply_ticket_status != 4) { + $new_status_name = escapeSql(getTicketStatusName($reply_ticket_status)); + logTicketHistory($ticket_id, "Status set to $new_status_name via the API ($api_key_name)"); + } - // Resolve the ticket, if set - if ($reply_ticket_status == 4) { + // Resolve the ticket, if it is actually moving into Resolved + if ($reply_ticket_status == 4 && $original_ticket_status != 4) { mysqli_query($mysqli, "UPDATE tickets SET ticket_resolved_at = NOW() WHERE ticket_id = $ticket_id AND ticket_resolved_at IS NULL LIMIT 1"); setTicketResolutionSlaMet($ticket_id); diff --git a/client/post.php b/client/post.php index 3f03302a7..d824709d6 100644 --- a/client/post.php +++ b/client/post.php @@ -105,9 +105,16 @@ if (isset($_POST['add_ticket_comment'])) { $ticket_reply_id = mysqli_insert_id($mysqli); // Update Ticket Last Response Field & set ticket to open as client has replied + $original_row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT ticket_status FROM tickets WHERE ticket_id = $ticket_id LIMIT 1")); + $original_ticket_status = intval($original_row['ticket_status'] ?? 0); + mysqli_query($mysqli, "UPDATE tickets SET ticket_status = 2 WHERE ticket_id = $ticket_id AND ticket_client_id = $session_client_id LIMIT 1"); syncTicketSlaClock($ticket_id); - logTicketHistory($ticket_id, "$session_contact_name replied from the client portal, reopening the ticket"); + + // Only record the reopen when the ticket was not already open + if ($original_ticket_status !== 2) { + logTicketHistory($ticket_id, "$session_contact_name replied from the client portal, reopening the ticket"); + } // Get ticket details & Notify the assigned tech (if any) diff --git a/cron/ticket_email_parser.php b/cron/ticket_email_parser.php index 5f63dad43..37fc7f3a2 100644 --- a/cron/ticket_email_parser.php +++ b/cron/ticket_email_parser.php @@ -356,7 +356,10 @@ function addReply($from_email, $date, $subject, $ticket_number, $message, $attac mysqli_query($mysqli, "UPDATE tickets SET ticket_status = 2, ticket_resolved_at = NULL WHERE ticket_id = $ticket_id AND ticket_client_id = $client_id LIMIT 1"); resetTicketResolutionSla($ticket_id); - logTicketHistory($ticket_id, "$from_email_esc replied by email, reopening the ticket"); + // Only record the reopen when the ticket was not already open + if (intval($ticket_status) !== 2) { + logTicketHistory($ticket_id, "$from_email_esc replied by email, reopening the ticket"); + } logAudit("Ticket", "Edit", "Email parser: Client contact $from_email_esc updated ticket $config_ticket_prefix$ticket_number_esc ($subject)", $client_id, $ticket_id); triggerCustomAction('ticket_reply_client', $ticket_id); From 6b65c8150fd5cd33bd05435dd13f850379b69a14 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 8 Aug 2026 12:58:46 -0400 Subject: [PATCH 21/25] Fix contact delete leaving an orphaned portal user and anonymize not redacting the phone number --- agent/post/contact.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/agent/post/contact.php b/agent/post/contact.php index ef2c95b9e..5b3b3e3dc 100644 --- a/agent/post/contact.php +++ b/agent/post/contact.php @@ -766,7 +766,7 @@ if (isset($_GET['anonymize_contact'])) { $contact_id = intval($_GET['anonymize_contact']); // Get contact & client info - $sql = mysqli_query($mysqli,"SELECT contact_name, contact_email, contact_client_id, contact_user_id FROM contacts WHERE contact_id = $contact_id"); + $sql = mysqli_query($mysqli,"SELECT contact_name, contact_email, contact_phone, contact_client_id, contact_user_id FROM contacts WHERE contact_id = $contact_id"); $row = mysqli_fetch_assoc($sql); $contact_name = escapeSql($row['contact_name']); @@ -938,7 +938,7 @@ if (isset($_GET['delete_contact'])) { $contact_id = intval($_GET['delete_contact']); // Get Contact Name and Client ID for logging and alert message - $sql = mysqli_query($mysqli,"SELECT contact_name, contact_client_id FROM contacts WHERE contact_id = $contact_id"); + $sql = mysqli_query($mysqli,"SELECT contact_name, contact_client_id, contact_user_id FROM contacts WHERE contact_id = $contact_id"); $row = mysqli_fetch_assoc($sql); $contact_name = escapeSql($row['contact_name']); $client_id = intval($row['contact_client_id']); From 46a63b191ce14ef59fdab82f5ce490285d20c077 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 8 Aug 2026 12:59:31 -0400 Subject: [PATCH 22/25] Fix bulk recurring ticket priority change denying access to all non-admin users --- agent/post/recurring_ticket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/post/recurring_ticket.php b/agent/post/recurring_ticket.php index 8ecb5946d..78589b190 100644 --- a/agent/post/recurring_ticket.php +++ b/agent/post/recurring_ticket.php @@ -566,7 +566,7 @@ if (isset($_POST['bulk_edit_recurring_ticket_priority'])) { $recurring_ticket_subject = escapeSql($row['recurring_ticket_subject']); $original_recurring_ticket_priority = escapeSql($row['recurring_ticket_priority']); - $client_id = intval($row['ticket_client_id']); + $client_id = intval($row['recurring_ticket_client_id']); enforceClientAccess(); From 04991a0d79255980f7346210d3a8006994ccbf19 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 8 Aug 2026 13:00:01 -0400 Subject: [PATCH 23/25] Fix ticket schedule cancellation never cancelling the calendar event --- agent/post/ticket.php | 10 ++++---- functions/app.php | 54 +++++++++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/agent/post/ticket.php b/agent/post/ticket.php index a8d9b85a7..85513ed6f 100644 --- a/agent/post/ticket.php +++ b/agent/post/ticket.php @@ -3062,7 +3062,7 @@ if (isset($_POST['edit_ticket_schedule'])) { /// Create iCal event - $cal_str = createiCalStr($schedule, $cal_subject, $cal_description, $cal_location); + $cal_str = createiCalStr($schedule, $cal_subject, $cal_description, $cal_location, getTicketCalendarUid($ticket_id)); // Notify the agent of the scheduled work $data[] = [ @@ -3183,7 +3183,6 @@ if (isset($_GET['cancel_ticket_schedule'])) { $ticket_number = intval($row['ticket_number']); $ticket_subject = escapeSql($row['ticket_subject']); $ticket_schedule = escapeSql($row['ticket_schedule']); - $ticket_cal_str = escapeSql($row['ticket_cal_str']); // Don't Enforce Client Access if Ticket doesn't have an assigned client if ($client_id) { @@ -3203,9 +3202,6 @@ if (isset($_GET['cancel_ticket_schedule'])) { $config_ticket_from_name = escapeSql($config_ticket_from_name); $session_company_name = escapeSql($session_company_name); - //Create iCal event - $cal_str = createiCalStrCancel($ticket_cal_str); - //Send emails $sql = mysqli_query($mysqli, "SELECT client_name, contact_email, contact_name, ticket_client_id, ticket_details, ticket_number, @@ -3229,6 +3225,10 @@ if (isset($_GET['cancel_ticket_schedule'])) { $user_name = escapeSql($row['user_name']); $user_email = escapeSql($row['user_email']); + //Create the iCal cancellation - same UID and subject as the original invite + $cal_subject = $ticket_number . ": " . $client_name . " - " . $ticket_subject; + $cal_str = createiCalStrCancel($ticket_schedule, $cal_subject, getTicketCalendarUid($ticket_id)); + // Notify the agent of the cancellation $data[] = [ // User Email diff --git a/functions/app.php b/functions/app.php index c285e976b..df45126dc 100644 --- a/functions/app.php +++ b/functions/app.php @@ -415,7 +415,16 @@ function addToMailQueue($data) { return true; } -function createiCalStr($datetime, $title, $description, $location) { +function getTicketCalendarUid($ticket_id) { + // An invite and its later cancellation MUST carry the same UID or the + // recipient's calendar client cannot match them up. Derive it from the + // ticket so it is stable across both, rather than from the current time. + $ticket_id = intval($ticket_id); + $host = $_SERVER['SERVER_NAME'] ?? 'itflow'; + return "ticket-$ticket_id@$host"; +} + +function createiCalStr($datetime, $title, $description, $location, $uid = null) { require_once "../libs/zapcal/zapcallib.php"; // Create the iCal object @@ -431,8 +440,11 @@ function createiCalStr($datetime, $title, $description, $location) { // Todo: adjust this for actual duration $event->addNode(new ZCiCalDataNode("DTEND:" . ZCiCal::fromSqlDateTime($datetime))); $event->addNode(new ZCiCalDataNode("DTSTAMP:" . ZCiCal::fromSqlDateTime())); - $uid = date('Y-m-d-H-i-s') . "@" . $_SERVER['SERVER_NAME']; + if (empty($uid)) { + $uid = date('Y-m-d-H-i-s') . "@" . ($_SERVER['SERVER_NAME'] ?? 'itflow'); + } $event->addNode(new ZCiCalDataNode("UID:" . $uid)); + $event->addNode(new ZCiCalDataNode("SEQUENCE:0")); $event->addNode(new ZCiCalDataNode("LOCATION:" . $location)); $event->addNode(new ZCiCalDataNode("DESCRIPTION:" . $description)); // Todo: add organizer details @@ -442,31 +454,27 @@ function createiCalStr($datetime, $title, $description, $location) { return $cal_event->export(); } -function createiCalStrCancel($originaliCalStr) { +function createiCalStrCancel($datetime, $title, $uid) { require_once "../libs/zapcal/zapcallib.php"; - // Import the original iCal string - $cal_event = new ZCiCal($originaliCalStr); + // Build the cancellation fresh. There is no stored copy of the original + // invite to reopen - the match is made by UID, not by the body. + $cal_event = new ZCiCal(); - // Iterate through the iCalendar object to find VEVENT nodes - foreach($cal_event->tree->child as $node) { - if($node->getName() == "VEVENT") { - // Check if STATUS node exists, update it, or add a new one - $statusFound = false; - foreach($node->data as $key => $value) { - if($key == "STATUS") { - $value->setValue("CANCELLED"); - $statusFound = true; - break; // Exit the loop once the STATUS is updated - } - } - // If STATUS node is not found, add a new STATUS node - if (!$statusFound) { - $node->addNode(new ZCiCalDataNode("STATUS:CANCELLED")); - } - } + // METHOD belongs on the VCALENDAR, not on the VEVENT + $cal_event->tree->data['METHOD'] = new ZCiCalDataNode("METHOD:CANCEL"); + + $event = new ZCiCalNode("VEVENT", $cal_event->curnode); + $event->addNode(new ZCiCalDataNode("UID:" . $uid)); + $event->addNode(new ZCiCalDataNode("SUMMARY:" . $title)); + if (!empty($datetime)) { + $event->addNode(new ZCiCalDataNode("DTSTART:" . ZCiCal::fromSqlDateTime($datetime))); + $event->addNode(new ZCiCalDataNode("DTEND:" . ZCiCal::fromSqlDateTime($datetime))); } + $event->addNode(new ZCiCalDataNode("DTSTAMP:" . ZCiCal::fromSqlDateTime())); + // Must outrank the invite's SEQUENCE:0 or clients ignore the cancellation + $event->addNode(new ZCiCalDataNode("SEQUENCE:1")); + $event->addNode(new ZCiCalDataNode("STATUS:CANCELLED")); - // Return the modified iCal string return $cal_event->export(); } From 6ff454134b1acf5189ecd3de5f6f4357710f4ec6 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 8 Aug 2026 13:14:25 -0400 Subject: [PATCH 24/25] Update changelog --- CHANGELOG.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 426ff3f7c..e4b9d3283 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,37 @@ This file documents all notable changes made to ITFlow. +## [26.08.1] Maint Release + +### Upgrading to 26.08.1 + +Update the files from Settings > Update as normal. This release moves the database to 2.6.7 and the web updater completes it for you — the command line step that 26.08 required is not needed again. + +### Breaking Changes and Notes + +- Client access: agents with restricted client access now see records that have no client assigned. Previously this varied by page — unassigned tickets and projects were visible, unassigned expenses and credentials were not. It is now consistent everywhere. + +### Bug Fixes +- Setup: fixed the wizard closing itself after the first user, which left new 26.08 installs stuck in a redirect loop between `/setup` and `/login.php`. +- API: tightened client scoping on the expense read and record update endpoints. +- Income: revenue rows now respect restricted client access. +- Client PDF Export: fixed the export producing a CSV file, and each section is now gated on the module that owns it. +- AI: fixed model creation, per-use-case model selection, configurable temperature, and error reporting. +- Ticket: system-generated replies no longer record time worked that was never worked. +- Ticket: fixed an error when scheduling a ticket. +- Ticket: cancelling a schedule now cancels the calendar event on the recipient's calendar. +- Ticket: history no longer records a status change when the status did not change. +- Recurring Ticket: bulk priority changes no longer deny access to agents who are not administrators. +- Contact: deleting a contact now removes the linked portal user, and anonymizing now redacts the phone number. +- Calendar: fixed event deletion. + +### New Features & Updates +- Performance: queries now select only the columns they use instead of `SELECT *`, cutting memory use and query time across the app and especially in the crons. +- Performance: removed client joins that were only there for scoping — side nav badge counts are significantly faster. +- Client scoping: added a `clientScopeSql()` helper so list queries scope on the owning column instead of a joined `clients.client_id`. +- Contributing: documented the column-selection and client-scoping conventions. + + ## [26.08] ### Upgrading to 26.08 From b903ee02fea699c20d6b36364b8fc9755ad60456 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 8 Aug 2026 13:15:24 -0400 Subject: [PATCH 25/25] Bump version --- includes/app_version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/app_version.php b/includes/app_version.php index 49e871292..188420bc1 100644 --- a/includes/app_version.php +++ b/includes/app_version.php @@ -5,4 +5,4 @@ * Update this file each time we merge develop into master. Format is YY.MM (add a .v if there is more than one release a month. */ -DEFINE("APP_VERSION", "26.08"); +DEFINE("APP_VERSION", "26.08.1");