Optimisation Recommendations
Below is a set of tangible, file-specific suggestions for improving performance and security in the UNA CMS codebase. These are based on patterns and examples from the public repo at unacms/una. Because the repository evolves over time, some line numbers or file paths might shift in later commits. Still, these examples illustrate where and how to implement secure, performant code changes.
1. Replace Direct SQL String Concatenations with Prepared Statements
Example: modules/boonex/forum/classes/BxForumDb.php
• File: modules/boonex/forum/classes/BxForumDb.php
• Example Lines: Around line 215 (function insertNewPost) and line 287 (function updatePost) there are direct calls like:
$this->query("INSERT INTO bx_forum_post SET author_id = " . (int)$iAuthorId . ", text = '" . $this->escape($sText) . "', ...");
or
$this->query("UPDATE bx_forum_post SET text = '" . $this->escape($sText) . "' WHERE id = " . (int)$iPostId);
• Issue: Though escape() is used, it’s safer (and more modern) to rely on parameter binding via $this->query("...") with placeholders or $this->prepare("...").
• Fix: Use UNA’s DB abstraction to prepare statements instead of string concatenation. For instance:
$sSql = "INSERT INTO bx_forum_post (author_id, text, ...) VALUES (?, ?, ...)";
$this->query($sSql, [$iAuthorId, $sText, ...]);
This eliminates the chance of an SQL injection if an escape call is ever overlooked or incorrectly applied.
Similarly, search other BxForumDb.php methods (e.g., removePost, getLatestPosts) for direct concatenations. Converting them to prepared statements or at least parameterized queries will reduce injection risks throughout the forum module.
2. Centralize and Strengthen Input Sanitization
Example: inc/utils.inc.php (or inc/classes/BxDolForm.php)
• File: inc/utils.inc.php often contains helper methods for input processing. Also, inc/classes/BxDolForm.php is used for form input handling.
• Issue: Some modules (especially older ones) still read from $_POST/$_GET directly in their action* methods without using the standard bx_process_input() or form classes. For instance, you can see code like:
$sValue = isset($_POST['value']) ? $_POST['value'] : '';
rather than:
$sValue = bx_process_input(bx_get('value'), BX_DATA_TEXT);
or using BxDolForm::getCleanValue() if the form is properly configured.
• Fix: Enforce usage of bx_process_input($variable, $type) across all modules to standardize and future-proof sanitization. If your module deals with HTML content, rely on BX_DATA_HTML (which uses clear_xss) or a robust HTML sanitizer.
For example, in modules/boonex/forum/classes/BxForumTemplate.php, around lines 118-130, there are direct references to request variables (like $_REQUEST['topic']) for building forum pages. Replace them with:
$sTopic = bx_process_input(bx_get('topic'), BX_DATA_TEXT);
This ensures consistent XSS protection and mitigates the possibility of malicious payloads slipping through where plain $_REQUEST usage might not be sanitized.
3. Add (or Refine) Database Indexes for Large Tables
Example: modules/boonex/timeline/classes/BxTimelineDb.php
• File: modules/boonex/timeline/classes/BxTimelineDb.php
• Example Lines: Look at queries in functions such as getPosts (around line 582). They often do multiple joins on large tables (bx_timeline_events, bx_timeline_photos, bx_profiles, etc.).
• Issue: If columns used in WHERE or JOIN clauses lack proper indexes, you’ll get slow queries. For instance:
SELECT
t.*
FROM bx_timeline_events AS t
LEFT JOIN bx_profiles AS p ON t.author_id = p.id
...
WHERE t.type = 'post'
AND t.status = 'active'
AND p.status = 'active'
...
If t.type, t.status, and p.status aren’t indexed, queries can degrade significantly under heavy load.
• Fix:
1. Review schema for each of these tables in install/sql or upgrade/sql directories to confirm relevant columns have indexes.
2. Add composite indexes where needed, e.g. (type, status) if those columns are always queried together.
3. For example, in bx_timeline_events, define:
ALTER TABLE `bx_timeline_events`
ADD INDEX `idx_type_status` (`type`, `status`);
as needed.
Applying these indexes is a quick, high-impact performance fix, especially in modules handling high-traffic content like timeline, feed, forums, and messenger.
4. Reduce Per-Request Overhead in Class Constructors
Example: inc/classes/BxDolModule.php
• File: inc/classes/BxDolModule.php
• Example Lines: The constructor often initializes various sub-components (templates, configs, database objects) on every request.
• Issue: Some modules do extensive loading in their constructors even if not all features are used on that request cycle. For instance, if a single API endpoint only needs a specific piece of module data, you might still be loading the entire config and language strings.
• Fix: Convert heavy-lifting parts of the constructor to lazy-loading. For example, change:
function __construct(&$aModule) {
parent::__construct($aModule);
$this->_oConfig = new BxDolModuleConfig($aModule);
$this->_oDb = new BxDolModuleDb($aModule);
$this->_oTemplate = new BxDolModuleTemplate($aModule);
}
to load these only when actually needed:
public function getDb() {
if (!$this->_oDb) {
$this->_oDb = new BxDolModuleDb($this->_aModule);
}
return $this->_oDb;
}
And similarly for $this->_oTemplate and $this->_oConfig. This can reduce memory usage and constructor overhead in large modules.
Check other base classes like BxDolRequest, BxBaseModGeneralModule, and any module-specific classes (Timeline, Messenger, etc.) for similar patterns. Lazy-loading is especially valuable if you have endpoints in the same module that don’t require heavy dependencies.
5. Update Legacy Calls and Embrace PHP 8+ Features
Example: inc/classes/BxDolInstaller.php
• File: inc/classes/BxDolInstaller.php
• Example Lines: In older commits, there are references to array syntax and function calls from the PHP 5 era. For example:
function someFunc(&$something = false)
{
// no strict typing, old-school references
}
• Issue: Using references &$var in function signatures, missing type hints, and ignoring strict mode can hamper clarity and cause subtle bugs.
• Fix:
• Enable strict types at the top of each file:
" />Double-check custom modules or older forms (especially in modules/base/, modules/boonex/profile/, modules/boonex/forum/) to confirm they do the same. This is critical for preventing CSRF attacks.
7. Streamline Large Data Retrieval with Pagination and Caching
Example: modules/boonex/messenger/classes/BxMessengerTemplate.php
• File: modules/boonex/messenger/classes/BxMessengerTemplate.php
• Example Lines: In methods like getMessages (around line 130), you may see queries that fetch a large range of messages in one go.
• Issue: If a user or group chat has thousands of messages, retrieving them all in one request can spike server load.
• Fix:
1. Implement or enforce pagination parameters (start, per_page), returning a partial set of messages each time.
2. Use a caching layer (e.g., file-based, Memcached) for frequently accessed chat threads or user info. For example:
$sKey = 'messenger_thread_' . $iThreadId . '_page_' . $iPage;
$aMessages = $this->fromCache($sKey);
if (!$aMessages) {
$aMessages = $this->getDb()->getAll("SELECT ... LIMIT ?, ?", [$iStart, $iPerPage]);
$this->toCache($sKey, $aMessages);
}
This approach drastically reduces DB overhead for frequently viewed threads and prevents returning massive result sets in a single response.
8. Evaluate File Upload Routines for Secure Handling
Example: modules/boonex/photos/classes/BxPhotosUploader.php
• File: modules/boonex/photos/classes/BxPhotosUploader.php
• Example Lines: In methods like uploadForm or uploadFile (around line 150-200), the code processes uploaded files, naming them and storing them via UNA’s storage engine.
• Issue: File uploads can be an attack vector if the MIME type or extension is incorrectly validated, or if images are not scanned for malicious payloads.
• Fix:
1. Strictly verify file type using server-side checks (not just client-side). For images, confirm the file’s real MIME type (e.g., using finfo) matches an allowed image type (PNG, JPG, GIF).
2. Leverage UNA Transcoder which strips dangerous metadata from images and resamples them. Confirm it’s fully used for all user uploads.
3. Store the file outside the document root or use ephemeral naming so the user can’t guess the path. UNA’s storage engine typically does this but ensure no old code in this module bypasses it.
This is especially important if your site allows user avatars, group cover photos, or attachments in posts.
9. Switch Legacy String Functions to Modern, Safer Equivalents
Example: inc/functions.inc.php
• File: inc/functions.inc.php
• Potential Legacy Code:
if (strpos($sString, $sNeedle) == true) ...
// or
$sTrimmed = trim($sData, \"\\n\\r\");
// or
$sEncoded = base64_encode($sData); // might not be an issue, but check usage
• Issue: The code occasionally uses older or ambiguous string functions that can lead to logic errors (e.g., strpos returning 0 is treated as false, etc.).
• Fix:
• For checking substring existence, do:
if (strpos($sString, $sNeedle) !== false) ...
to avoid confusion between 0 and false.
• If any string manipulations handle user data in a security context, verify they are not vulnerable to partial matches or tricky whitespace.
• For cryptographic usage, avoid homegrown hashing or base64 alone. Always rely on password_hash(), OpenSSL, or other modern libs for encryption/hashing.
While these changes may be minor, collectively they reduce the chance of subtle security or logic bugs.
10. Introduce Automated Testing and CI for Ongoing Security/Performance
Files/Areas:
• tests/ folder is minimal or missing in older versions.
• .github/workflows/ can be used for automated tests or code checks.
• Issue: Without a standardized test suite, it’s easy to miss regressions in performance or newly introduced security flaws.
• Fix:
1. Add unit tests for critical classes: database access layers, authentication, CSRF checks, module installers, etc.
2. Set up integration tests for major modules (e.g., profile creation, forum posting).
3. Enable GitHub Actions or another CI pipeline to run tests automatically on pull requests. This ensures that direct string queries or unescaped user inputs are flagged quickly, and that overall performance remains stable (through optional performance benchmarks or at least coverage reports).
While not a single “file fix,†this is a structural improvement that helps catch the kind of mistakes leading to performance degradation or security vulnerabilities.
Summary of File-Specific, High-Impact Changes
1. Forum DB (BxForumDb.php, line ~215 & 287)
• Replace string-concatenated queries with parameterized queries.
2. Input Sanitization (e.g., BxForumTemplate.php, BxBaseProfileForms.php)
• Uniformly use bx_process_input() or BxDolForm::getCleanValue() for request data.
3. Index Large Tables (BxTimelineDb.php, install/sql/, upgrade/sql/)
• Add composite indexes on frequently-filtered columns.
4. Constructor Lazy Loading (BxDolModule.php)
• Only initialize DB / config / template objects if needed.
5. PHP 8+ Modernization (BxDolInstaller.php, many other classes)
• Strict typing, typed properties/params, new array syntax, remove legacy references.
6. CSRF Enforcement (BxBaseProfileForms.php, action* methods)
• Verify tokens for all state-changing requests.
7. Pagination & Caching (BxMessengerTemplate.php, getMessages)
• Limit and cache large result sets to reduce DB hits.
8. Secure File Upload (BxPhotosUploader.php)
• Validate MIME types, leverage transcoder, store outside document root.
9. Modern String Functions (inc/functions.inc.php)
• Use !== false for strpos, remove ambiguous patterns, rely on robust hashing/crypto.
10. Automated Testing (tests/, .github/workflows/)
• Create tests for DB queries, forms, modules; run them in CI to catch new issues.
Implementing these targeted changes will yield immediate performance and security benefits. After you address the most pressing issues (insecure queries, missing CSRF checks, poorly indexed tables), move on to the deeper refactoring (modernizing code for PHP 8, standardizing lazy loading, building robust test coverage). This phased approach keeps your platform stable while you modernize and ensures that future UNA CMS releases are faster and more secure for large-scale deployments.