Журнал изменений
Condense the inline comment for the PATH_INFO rejection block to a concise single-line description.
Core changes:
- Comment update (security.php):
Replace verbose multi-clause comment with shorter form
- Keeps same technical meaning in fewer words
Add detailed test suite descriptions covering all Unit and Validation tests, including the new safety net tests for Phase 1 refactoring.
Core changes:
- Test documentation (docs/TESTS.md):
Add Test Suites section with two subsections: Unit and Validation
- List every test file with test count and purpose
- Include PasswordHashTest, InputFilterTest, TemplateIfTest
- Add commands for running individual suites and files
Benefits:
- New contributors can quickly understand test coverage
- Clear mapping between test files and CMS components
Add 41 new unit tests covering password hashing, input filtering, and template conditionals to establish a regression baseline before the upcoming security hardening changes.
Core changes:
- Password hash tests (PasswordHashTest.php):
Verify md5_salt() algorithm: md5(md5(salt) . md5(pass))
- Consistency, hex format, salt dependency, known values
- Unicode and special character handling
- Validate future bcrypt format for migration readiness
- Input filter tests (InputFilterTest.php):
- num_filter: digit extraction, non-numeric handling, edge cases
- var_filter: allowed chars, Unicode support, XSS prevention
- isVar: alphanumeric validation, array handling
- text_filter: HTML escaping, BBCode stripping, type modes
- url_filter: protocol prefixing, empty handling
- save_text: quote/dollar/backslash escaping
- Template conditional tests (TemplateIfTest.php):
setTemplateIf: true/false branches, else blocks
- Nested conditions, string true/false coercion
- Undefined flags, multiple independent ifs
- Whitespace tolerance in tags
Benefits:
- Regression safety net before password_hash migration
- Baseline for eval() removal in template system
- Validates filter behavior before SQL parameterization
Technical notes:
- Uses algorithm replicas to avoid system.php dependency chain
- All 113 project tests pass (54 new + 59 existing)
- No changes to production code
Add early rejection of index.php/... style URL requests that could bypass CMS routing and expose internal query parameters.
Core changes:
- Request validation (security.php):
Detect PATH_INFO tricks via $_SERVER['PATH_INFO'] and URL pattern
- Returns 404 for /index.php/name=files&op=view style requests
- Prevents URL-based parameter injection bypass
Benefits:
- Blocks a class of URL manipulation attacks
- No impact on normal CMS operation
Technical notes:
- Runs before any routing or module loading
- Sets $_GET['error'] = 404 for CMS error page handling
- Compatible with all PHP versions >= 8.1
Admin editor flag $admin[3] was accessed without null check in admin.php and had inconsistent default value (1) in system.php textarea functions.
Core changes:
- Admin editor flag guard (core/admin.php):
Add isset($admin[3]) check with default 0
- Prevents potential warning if admin session data is incomplete
- Normalize editor defaults (core/system.php):
Change default from 1 to 0 in textarea() and textareae()
- Aligns with security.php pattern: ($admin[3] ?? '') -> (int)'' = 0
- Default 0 = no visual editor when flag unavailable
Benefits:
- Consistent default behavior across all $admin[3] access points
- Defensive coding against incomplete session data
Technical notes:
- $admin[3] stores editor flags, first char = visual editor toggle
No runtime errors observed yet (admin always authenticated), but guards added for robustness and PHP 8.1+ strict compliance
Guest/bot visitors triggered 4300+ "Undefined array key 3" warnings daily because $user is an empty array for non-authenticated visitors, but $user[3] (story number preference) was accessed without null check.
Core changes:
- Module pagination calls (11 modules):
Add null coalescing default: $user[3] ?? 0
- forum, files, links, pages, faq, shop, media, jokes, help,
auto_links, account
- Consistent numeric default 0 for user_news() parameter
- getUserNews function (core/system.php):
Extract $user[3] ?? 0 into local variable $unum
- Prevents potential warning in direct array access
- Maintains existing !empty() fallback logic
Benefits:
- Eliminates most frequent error in production logs (4321 occurrences)
- Clean PHP 8.1+ compatibility for guest/bot traffic
- No behavioral change for authenticated users
Technical notes:
$user array is [] for guests (security.php:71), cannot be padded with defaults because if ($user) login checks rely on empty array
- user_news() already handles empty $unum via !empty() check
RSS feeds returned SQL syntax errors for all module types (news, files, pages, shop, faq) due to missing $confrs variable in function scope, causing truncated LIMIT clause. SQL error logging was also corrupted by text_filter() stripping <= operators from logged queries.
Core changes:
- RSS feed SQL fix (core/user.php):
Add $confrs to global declaration in rss_channel()
- require_once was skipped because rss.php already loaded in system.php
- $confrs undefined caused $num=null, producing "LIMIT " without value
Replace deprecated $_GET access with null coalescing operator
- $_GET['name'], $_GET['cat'], $_GET['num'], $_GET['id']
- SQL error logging fix (core/security.php):
Replace text_filter() with htmlspecialchars() in error_sql_log()
- text_filter() used strip_tags() which treated <= as HTML tag
- All SQL after <= NOW() was silently stripped from error logs
Benefits:
- RSS feeds now work correctly for all module types
- SQL error logs show complete, untruncated queries
- Eliminates PHP 8.1+ undefined array key warnings in RSS
Technical notes:
Root cause: system.php:35 loads rss.php globally, require_once in rss_channel() was a no-op, $confrs stayed undefined in function scope
- Affected ~30+ SQL errors per day from bot/crawler RSS requests
Exclude Composer binary from version control as it should be installed separately on each machine, not shipped with the project.
Restore the SEO configuration file that was previously merged into core/system.php, keeping config separate from core logic.
Core changes:
- SEO configuration (config/config_seo.php):
Restore $confse array with all SEO settings
- URL rewrite toggle and separators
- Keyword generation settings (count, length, shuffle)
- Auto-description and long title options
- Open Graph meta tags template
- Schema.org structured data template
Benefits:
- Keeps configuration separate from core system code
- Easier to edit SEO settings without touching system.php
- Consistent with other config files (modules, comments, etc.)
Add PHPUnit test to prevent require/include statements from being placed inside functions, which causes silent failures with require_once.
Core changes:
- testNoIncludesInsideFunctions (SecurityValidationTest.php):
Uses PHP tokenizer (token_get_all) for accurate detection
- Tracks brace depth to determine function scope
- Detects T_REQUIRE, T_REQUIRE_ONCE, T_INCLUDE, T_INCLUDE_ONCE
- Reports file path, line number, and function name on failure
- Scans all project PHP files (excludes vendor, tests, setup)
Benefits:
- Prevents recurring require_once-inside-function bugs
- Catches issues at test time before they reach production
- Accurate scope detection via PHP tokenizer vs regex
Technical notes:
- Tokenizer approach handles edge cases (comments, strings)
- Test integrates with existing SecurityValidationTest file scanner
- No false positives for top-level includes or class method bodies