- Rename methods to camelCase (PSR-12): parseAttributeSearch, searchByAttributes, searchByAttributeValue, getAttributeSortDefinitionId
- Rename variables to camelCase (PSR-12)
- Add DATE attribute search support in searchByAttributeValue
- Fix get_definitions_by_flags to request typed payload (second param true)
- Handle both array and string return shapes for definition info
- Fix term-only search to merge with attribute matches instead of replacing
- Use strict emptiness checks (=== '' instead of empty())
- Sanitize definition_ids before SQL interpolation (array_map intval)
- Include DATE in attribute search conditions
- Fix PHPDoc comment format in item_sort_columns() helper
- Remove duplicate blank line after properties in Item model
- Remove unused variable assignment in Items controller
- Add item_sort_columns() helper function in tabular_helper.php
- Helper returns all sortable columns including dynamic attribute IDs
- Remove duplicate sanitizeSortColumnAttribute method from Items controller
- Remove unused ALLOWED_SORT_COLUMNS constant from Item model
- Reuses existing sanitizeSortColumn method from Secure_Controller
- Add Item::ALLOWED_SORT_COLUMNS constant for allowed sort columns
- Use constant in sanitizeSortColumnAttribute() instead of inline array
- Enables reuse across the codebase for sort column validation
Phase 3 - Multi-attribute Search:
- Add parse_attribute_search() method to parse search syntax like
'color: blue size: large' or 'color:blue AND size:large'
- Update search_by_attributes() to support AND/OR logic for multiple
attribute queries
- Add search_by_attribute_value() private method for single value search
Phase 4 - Sort by Attribute Columns:
- Add get_attribute_sort_definition_id() method to detect attribute
column sorting
- Update Item::search() to join attribute tables when sorting by
attribute columns
- Update tabular_helper to make attribute columns sortable
- Add sanitizeSortColumnAttribute() method in Items controller to
validate attribute definition IDs as sort columns
Fixes#2722 - sorting by attribute columns now works
- Add new search_by_attributes() method that returns matching item_ids
- Refactor search() method to use subquery approach instead of HAVING LIKE
- Fix pagination count issue (#2819) - get_found_rows() now returns correct count
- Enable combined search (attributes OR regular fields)
- GROUP_CONCAT still used for display but removed from search/count logic
- Fixes#2407 - multi-attribute search now works correctly
Related: #2819, #2407, #2722, #2919
* Fix SQL injection in suggestions column configuration
The suggestions_first_column, suggestions_second_column, and
suggestions_third_column configuration values were concatenated
directly into SQL SELECT statements without validation, allowing
SQL injection attacks through the item search suggestions.
Changes:
- Add whitelist validation in Config controller to only allow
valid column names (name, item_number, description, cost_price,
unit_price)
- Add defensive validation in Item model's get_search_suggestion_format()
and get_search_suggestion_label() methods
- Default invalid values to 'name' column for safety
- Add unit tests to verify malicious inputs are rejected
This is a critical security fix as attackers with config permissions
could inject arbitrary SQL through these configuration fields.
Vulnerability reported as additional injection point in bug report.
* Refactor: Move allowed suggestions columns to Item model constants
Extract the list of valid suggestion columns into two constants in the Item model for better cohesion:
- ALLOWED_SUGGESTIONS_COLUMNS: valid column names
- ALLOWED_SUGGESTIONS_COLUMNS_WITH_EMPTY: includes empty string for config validation
This consolidates the validation logic in one place and makes it reusable across Config controller and Item model.
* Address PR review comments: improve validation and code quality
Changes:
- Use camelCase naming for validateSuggestionsColumn() method (PSR-12)
- Add field-aware validation with different fallbacks for first vs other columns
- Handle non-string POST input by checking is_string() before validation
- Refactor duplicate validation logic into suggestionColumnIsAllowed() helper
- Use consistent camelCase variable names ($suggestionsFirstColumn)
- Update tests to validate constants and behavior rather than implementation
- Tests now focus on security properties of the allowlist itself
The validation now properly handles:
- First column: defaults to 'name' when invalid
- Second/Third columns: defaults to '' (empty) when invalid
- Non-string inputs: treated as invalid with appropriate fallback
---------
Co-authored-by: Ollama <ollama@steganos.dev>
The bulk edit function iterated over all $_POST keys without a whitelist,
allowing authenticated users to inject arbitrary database columns (e.g.,
cost_price, deleted, item_type) into the update query. This bypassed
CodeIgniter 4's $allowedFields protection since Query Builder was used
directly.
Fix: Add ALLOWED_BULK_EDIT_FIELDS constant to Item model defining the
explicit whitelist of fields that can be bulk-updated. Use this constant
in the controller instead of iterating over $_POST directly.
Fields allowed: name, category, supplier_id, cost_price, unit_price,
reorder_level, description, allow_alt_description, is_serialized
Security impact: High (CVSS 8.1) - Could allow price manipulation and
data integrity violations.
The previous SQL injection fix (GHSA-hmjv-wm3j-pfhw) used named parameter
syntax :search: with having(), but CodeIgniter 4's having() method does
not support named parameters. This caused the query to fail.
The fix uses havingLike() which properly:
- Escapes the search value to prevent SQL injection
- Handles the LIKE clause construction internally (wraps value with %)
- Works correctly with HAVING clauses for aggregated columns
This maintains the security fix while actually working on CI4.
Parameterize LIKE queries in HAVING clause to prevent SQL injection
when search_custom filter is enabled. Also sanitize search parameter
input at controller level for defense-in-depth.
Fixes vulnerability where user input was directly interpolated into
SQL queries without sanitization.
* Improve code style and PSR-12 compliance
- refactored code formatting to adhere to PSR-12 guidelines
- standardized coding conventions across the codebase
- added missing framework files and reverted markup changes
- reformatted arrays for enhanced readability
- updated language files for consistent styling and clarity
- minor miscellaneous improvements
* Remove HtmlPurifier calls
- All calls to Services::htmlPurifier()->purify() removed from data received from view.
- Bootstrap and bootswatch bump in package-lock.json
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Pre-view filtering Items Controller
- Refactored code for clarity
- Created and called sanitization functions.
- Sanitize TEXT type Attributes before being sent to the view.
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Pre-view filtering Customers Controller
- Refactored code for clarity
- Replaced == with === operator to prevent type juggling
- Added Sanitization of Customer data before being sent to the view
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Bump bootstrap-table to 1.23.1
- Bump bootstrap-table to 1.23.1 in attempt to resolve issue with sticky headers
- Sanitize attribute data in tables
- Sanitize item data with controller function.
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Pre-view filtering Items Controller
- Refactored code for clarity
- Created and called sanitization functions.
- Sanitize TEXT type Attributes before being sent to the view.
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Sanitize Item data
- Sanitize category and item_number before display in forms.
- refactor check in pic_filename for empty to be best practices compliant.
- Added TODO
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Minor changes
- Refactored for code clarity.
- Removed extra blank lines.
- Minor reformatting.
- Added PHPdocs
- bumped bootstrap-table to 1.23.2
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Pre-view filtering Items Controller
- Refactored code for clarity
- Created and called sanitization functions.
- Sanitize TEXT type Attributes before being sent to the view.
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Sanitize Item data
- Sanitize category and item_number before display in forms.
- refactor check in pic_filename for empty to be best practices compliant.
- Added TODO
Signed-off-by: objecttothis <objecttothis@gmail.com>
---------
Signed-off-by: objecttothis <objecttothis@gmail.com>
Co-authored-by: objecttothis <objecttothis@gmail.com>
- Added TODO where we need to convert to querybuilder
- Converted to switch statement.
- Removed unnecessary local variable
- Replaced Qualifiers with imports
- Replaced isset() call with null coalescing operator
- Replaced strpos function calls in if statements with str_contains calls
- Removed unnecessary leading \ in use statement
- Replaced deprecated functions
- Updated PHPdocs to match function signature
- Added missing type declarations
- Made class variables private.
- Explicitly declared dynamic properties
- use https:// links instead of http://
- Fixed type error from sending null when editing transactions
- Fixed Search Suggestion function name in Employees, Persons, Suppliers controller
- Fixed function name on Receivings Controller
Signed-off-by: objecttothis <objecttothis@gmail.com>
- Added filtering to decimals which may have different comma separator
- Added formatting of decimals before concatenating into string
- Cast int to string in form_hidden() call
Signed-off-by: objecttothis <objecttothis@gmail.com>
- Made view CI form helper function call format uniform.
- replaced calls to array() with []
- Placed { on its own line
- Removed empty lines where there shouldn't be any.
- Replaced text/javascript with application/javascript as the former is deprecated
Attributes: Noticed log_message() being called with uppercase letters in the level which causes errors in the system; Customers: improved the layout of the stats page in the information dialog issue 3892; Items: got csv import working issue 3896 and bulk edits working - barcode generation does not work yet.
- Removed unnecessary ReflectionException in PHPdoc
- Corrected return details of insert function
- Replaced deprecated class
- Removed Inventory model's insert function because it wasn't providing functionality that the Model class wasn't.
- Corrected the calling method signature for Inventory->insert()
- Added missing PHPdocs
- Corrected Syntax
- Added noinspection parameters to PHPdoc for AJAX called functions
- Added missing function return types
- Added missing parameter types
- Added public keyword to functions without visibility modifier
- Corrected incorrectly formatted PHPdocs
- Added public to constants and functions missing a visibility keyword
- Replaced TRUE/FALSE constants with true/false keywords
- Replaced NULL constant with null keyword
- Replaced `<?php echo` in views with shortened `<?=`
- Added missing variable declaration
- Added missing function return type in declaration
- replaced `== true`, `== false`, `=== true` and `=== false` in if statements with simplified forms
- Declared variable in view coming down from controller
- refactored javascript variable name to remove duplicate declaration warning
- Import missing class
- when the payments array was folded into sale_data there was an earlier payments[] reference in the foreach loop that didn't get folded in.
- Update PHPdoc
- Added ::class to remove polymorphic call warning
- Removed unreachable 'break;' statement after return statement.
- Added missing return type
- fixed missing assignment of mailchimp_api_key