Replace deprecated WHOIS server hostnames with current IANA-registered endpoints and add proper timeout and error handling for fsockopen calls in the whois module to prevent hanging requests and PHP warnings.
Core changes:
- WHOIS server registry (modules/whois/index.php):
- ru: whois.ripn.net → whois.tcinet.ru
- com/net: whois.crsnic.net → whois.verisign-grs.com
- org: whois.publicinterestregistry.net → whois.publicinterestregistry.org
- info: whois.afilias.net → whois.nic.info
- de: whois.nic.de → whois.denic.de
- ws: whois.nic.ws → whois.website.ws
- cn: whois.cnnic.net.cn → whois.cnnic.cn
- in/co.in/firm.in/gen.in/ind.in/net.in/org.in: whois.registry.in → whois.nixiregistry.in
- Connection handling (modules/whois/index.php):
- Add 10s timeout to all fsockopen calls
- Replace @ suppression with set_error_handler/restore_error_handler
- Remove redundant double-connect retry in whois()
- Variable rename (admin/modules/admins.php):
- $aroute → $afile for consistency with codebase convention
Benefits:
- WHOIS lookups no longer fail silently due to dead server hostnames
- Requests no longer hang indefinitely on unreachable servers
- No @ error suppression in compliance with project guardrails
Update .gitignore and project structure to reflect the transition from the legacy .rules/ directory to the new .agents/ convention for storing AI-workflow configuration. The git-rules.md file is removed as its content is superseded by the updated agent knowledge base.
Core changes:
- Ignored paths (.gitignore):
Add AGENT.md to ignored files
- Prevents session-specific agent manifests from being tracked
Add .agents/ directory to ignored paths
- Covers the new convention for AI workflow files
Remove .rules/ from ignored paths
- Directory is no longer used; rule files moved to .agents/
- Removed file (.rules/git-rules.md):
Delete legacy git commit rules document
- Rules are now maintained inside the .agents/ knowledge base
Benefits:
- Consistent project layout aligning with current AI workflow conventions
- Eliminates stale .rules/ directory from the repository
- .gitignore accurately reflects the real project structure
Technical notes:
- No functional code changes; configuration and documentation only
- Backward compatibility: unaffected
Four root markdown files updated to reflect the current state of the 6.3 codebase: corrected typos, updated progress percentage, unified log file extensions to .log, and added the logging hardening changelog that was missing from SECURITY.md.
Core changes:
- README.md:
- Progress badge and text updated from ~65% to ~70%
- chmod example: storage/logs/.txt → storage/logs/.log
- Typo PREFIX_DB corrected (was REFIX_DB in SQL code example)
- CONTRIBUTING.md:
- chmod example: storage/logs/.txt → storage/logs/.log
- All code examples use $afile (current canonical variable)
- Typo PREFIX_DB corrected in SQL example
- SECURITY.md:
- Typo PREFIX_DB corrected in SQL example
- Module count corrected: "27 modules" → "23 admin modules"
Added Logging & Error Handling Hardening subsection under v6.3.0:
- set_exception_handler(), register_shutdown_function()
- Extended set_error_handler() error levels
- Log rotation fix, .txt → .log rename, addCompress() migration
- Unified log_size 10 MB and filesize() >= operator
- UPGRADING.md:
- chmod example: storage/logs/.txt → storage/logs/.log
- Status text updated from ~65% to ~70%
- Typo PREFIX_DB corrected in SQL example
Troubleshooting log paths corrected:
- storage/logs/error.log → error_php.log and error_site.log
- Renamed Files section: added all 5 log file renames (.txt → .log)
Benefits:
- Documentation is consistent with current codebase
- No misleading typos or outdated paths in public-facing docs
- Logging hardening changes are now traceable in SECURITY.md
Technical notes:
- $afile is the current canonical variable (replaces deprecated $admin_file)
- All log channels now use storage/logs/ with .log extension
The visitor counter / statistics block in head() contained several reliability bugs: unguarded file reads, magic flock numbers, broken date comparison, unsafe $con array access, and missing directory guard before monthly archive rename.
Core changes:
- File read guard (core/system.php):
file($spath.'statistic.log') → file_exists() check before file()
- Prevents PHP warning when statistic.log does not yet exist
- flock constants (core/system.php):
- Magic numbers 2 and 3 → LOCK_EX and LOCK_UN for clarity
- $con array fallbacks (core/system.php):
All $con[N] accesses guarded with ?? 0 to prevent undefined offset notices
- $con[1], $con[3], $con[4], $con[5], $con[6], $con[7]
- $guest variable fix (core/system.php):
- !empty($guest) 1 → $guest 1 (double-negation logical error corrected)
- Date comparison fix (core/system.php):
String date comparison replaced with filemtime($slog) < strtotime('today midnight')
- Correct cross-midnight detection without locale-dependent string compare
- Directory guard before monthly archive (core/system.php):
- mkdir($sdir, 0755, true) added if statistic/ subdirectory does not exist
- Guarded unlink() calls (core/system.php):
- unlink(ips.log) and unlink(user.log) wrapped in file_exists() checks
Benefits:
- No PHP warnings on first-run or missing log files
- Correct guest/session detection logic
- Safe monthly archive creation even on fresh installations
- Code intent made explicit via named constants
Technical notes:
- statistic.log format unchanged: d.m.Y|hosts|hits|allhits|engines|refers|homereqs|users
- COUNTER_DIR constant must point to storage/counter/
All 6 log functions unified and hardened: paths moved to LOGS_DIR, extensions renamed from .txt to .log, rotation logic corrected with proper fclose-before-compress pattern, and exception/fatal-error handlers added for complete error coverage.
Core changes:
- Log path and extension migration (core/security.php):
config/logs/.txt → LOGS_DIR/.log for all 6 channels
- log.log, error_site.log, error_sql.log, hack.log, warn.log, error_php.log
- Log rotation hardening (core/security.php):
zip_compress() + unlink() → addCompress(dir, src, name, 'auto', true, true)
- Proper fclose() before compression in all 6 functions
- fopen() re-check after rotation (fhandle !== false guard)
- log_size fallback unified to 10 MB (was 1 MB in log_report)
- filesize() comparison unified to >= (was inconsistent > vs >=)
- Archive timestamp format unified to Y-m-d_H-i-s
- Error handler extensions (core/security.php):
- set_exception_handler() added — catches all uncaught exceptions → error_php.log
- register_shutdown_function() added — catches E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR
set_error_handler() extended: cases 256 (USER_ERROR), 512 (USER_WARNING), 1024 (USER_NOTICE), 4096 (RECOVERABLE_ERROR), 16384 (USER_DEPRECATED)
- Variable shadowing fixed in error_sql_log(): $log parameter renamed to $sql
Benefits:
- Fatal errors and uncaught exceptions now logged reliably
- No file corruption from compress-while-open race condition
- All log channels use consistent paths and size limits
- Archives carry second-precision timestamps to prevent collisions
Technical notes:
- LOGS_DIR constant must point to storage/logs/
- addCompress() with $del=true handles archive and source deletion atomically
- error_php.log used for both exception handler and shutdown function
Adds explicit eol=lf rules for all relevant text file types and marks binary assets to prevent line ending conversion.
Core changes:
- .gitattributes:
- Added global fallback: * text=auto eol=lf
- Added eol=lf for html, css, js, json, sql, xml, tpl, md, txt, ini, yaml, .htaccess
Added binary markers for images, fonts, archives, pdf
- Prevents Git from treating binaries as text and corrupting them
Benefits:
- Consistent LF line endings across all editors and OS
- No CRLF creep on Windows checkouts
- Binary files protected from line ending conversion
Fixes error suppression, inconsistent comparisons and naming in the PHP error log rotation block of error_reporting_log().
Core changes:
- error_reporting_log() (core/security.php):
Removed @ from fopen() calls, replaced with explicit !== false checks
- Follows rule 2.8: never use error suppression operator
- Renamed \$path -> \$log for consistency with addErrorFile() in system.php
Moved \$cfg = \$conf['security'] ?? [] inside if (\$error_write) block
- \$cfg only needed when actually writing; skipped for NOTICE etc.
- Extracted \$max = \$cfg['log_size'] ?? 10485760 as named variable
- Changed filesize comparison > to >= (consistent with addErrorFile())
Replaced \$ts/\$rot pattern with clean \$safe via pathinfo()
- Result: error_php_2024-01-01_12-00-00.zip instead of error_php.log.20240101_120000.zip
- Updated addCompress() call to use \$bak=true for .bak fallback
Benefits:
- No error suppression antipattern
- Consistent variable naming across both log rotation functions
- Cleaner archive filenames without double extension
- .bak fallback guaranteed when no compression available
Technical notes:
- Behavior identical when fopen() succeeds and compression is available
- \$cfg scoped to write path only: minor efficiency gain on non-write errors
Addresses multiple correctness and safety issues in the compression and error-logging pipeline discovered during systematic code review.
Core changes:
- addCompress() (core/system.php):
Added bool \$bak = false parameter for .bak fallback on no-compression
- When \$algo === 'none' and \$bak=true: rename source to name.bak
- Replaces broken array_intersect_key logic in callers
Replaced temp-file ZIP string path with addFromString()
- Eliminates temp file creation, write, and cleanup risk
Added unlink() result check in ZIP file and gz/bz2 delete branches
- Logs _ERR_DELETE on failure instead of silently ignoring
- addErrorFile() (core/system.php):
Added static \$running recursion guard
- Prevents addCompress->addErrorFile->addCompress infinite loop
- Falls back to error_log() on recursive call
- Replaced hardcoded 10485760 with \$conf['security']['log_size']
Replaced broken checkCompress()/array_intersect_key rotation block
- New: addCompress(..., 'auto', true, true) with .bak fallback
- addFile() (core/system.php):
Fixed bool-to-int coercion: return addCompress() ? 0 : 3
- Previously false coerced to 0, masking compression errors
- addBackupDb() (core/system.php):
Return value of addCompress() now checked
- Returns false on compression failure instead of silently succeeding
Benefits:
- Eliminates infinite recursion risk in error logging
- Consistent error codes in addFile() (0=ok, 1=read, 2=write, 3=compress)
- No temp file leaks in ZIP string compression path
- .bak fallback guaranteed when no compression extension available
Technical notes:
- \$bak parameter default false: backward compatible for all existing callers
- Recursion guard uses static variable: resets correctly after each call
Replaces the unconditional chmod() calls with an ownership-aware guard using posix_geteuid(). This prevents the function from silently failing or changing permissions on files owned by another process, and eliminates string-based octal literals in favor of proper octdec() conversion for reliable permission mode handling.
Core changes:
- Permission checker (core/system.php):
Replaced string octal '0'.\$chm with octdec((string)\$chm)
- Ensures valid integer mode is passed to chmod()
- Added posix_geteuid() call with graceful fallback (-1) when unavailable
- Added file_put_contents() return value check before proceeding
Added fileowner() comparison against current process UID
- chmod() on temp probe file only when owned by current process
- Falls back to is_writable() when posix functions unavailable
Applied same ownership check before chmod() on target directory
- \$cdir guards chmod(\$dir, \$mode) analogously to probe file guard
Moved unlink() inside the file_put_contents() success branch
- Prevents unlink() attempt when file creation failed
Benefits:
- Eliminates silent chmod() failures on foreign-owned files
- Correct permission integer conversion via octdec()
- Robust probe-file lifecycle (create, test, cleanup on success only)
Technical notes:
- posix_geteuid() may not be available on Windows; -1 signals fallback
- Behavior unchanged when process owns all files and chmod is supported
Prevents undefined index notices when \$confst or \$confr are not initialized or incomplete. The shop module similarly guards against a missing 'defis' key in \$confso by falling back to \$conf['defis'] and then a safe default. Both fixes align with the project's pattern of defensive config access.
Core changes:
- Admin info panel (core/admin.php):
Added \$confst to global variable declaration in admininfo()
- Was missing, causing potential undefined variable notice
Guarded \$confst['stat'] with is_array() + isset() check
- Falls back to 0 if key is absent
Guarded \$confr['refer'] with is_array() + isset() check
- Falls back to 0 if key is absent
- Shop module (modules/shop/index.php):
Replaced direct \$confso['defis'] with null-coalescing expression
- Falls back to \$conf['defis'] then '-' as safe default
- Applied consistently in shop() and view() functions
Benefits:
- Eliminates undefined index PHP notices in admin dashboard
- Safe fallback for missing shop separator config
- Consistent defensive config access pattern
Technical notes:
- No functional behavior change when config keys are present
- Backward compatible with existing config structures