e107 v2.3.6
Caution
v2.3.6 is a bug-fix release for sites on v2.3.5 or earlier.
Upgrade from v2.3.5 or earlier 2.x. If your site tracks the master branch, you are already past v2.3.6, so installing it would be a downgrade. v2.4.x is planned to be the next forward step.
Highlights
- [Security] Command injection in
resize_image()(GHSA-3j33-c9v4-4p42). The ImageMagickconvertcommand line did not shell-escape its destination filename; reachable via news submission with the right combination of prefs. (794a179f) - Host-header recovery for sites locked out by v2.3.4 / v2.3.5. The GHSA-7pmw-jwvr-cq2x killswitch now case-folds, strips
www., and strips trailing ports before comparison, and returns a logged 503 instead of a baredie(). Closes #5627 and #5634. (aba3b169) trusted_hostsSitePref for parked, staging, and multi-host setups. Authorise additional incoming hostnames from Admin → Preferences without touchinge107_config.php. (c2bb246b)- PHP 8 fatal-error sweep.
thumb.php(#5664),fpw.phpon v1-style themes (#5653), the FAQ cron registration, and the admin nav / user-handler bare-constant reads all stop crashing on PHP 8. (59aef4f1, 02a79729, 0635801a, b1290139)
For Administrators
Added
trusted_hostsSitePref. New textarea below the Site URL row in Admin → Preferences. Paste additional hostnames one per line (e.g.staging.example.com,example.org); the server-side normaliser strips schemes/paths and de-duplicates case-insensitively, sohttps://staging.example.com/saves asstaging.example.com. The pref is purely additive: requests whoseHostmatches the configuredsiteurlcontinue to pass without listing it here. Ref GHSA-7pmw-jwvr-cq2x, #5627. (c2bb246b)
Changed
-
Host-header validation (security).
www.and the bare apex now match each other, hostnames compare case-insensitively, and trailing ports are stripped before comparison, sohttps://example.com:8080/matcheshttps://example.com/. Sites that were stuck on the "Site Configuration Issue Detected" page after upgrading from v2.3.3 should now boot again without manual SQL edits.The check itself still requires the request
Hostto match the configuredsiteurl(or fall under one of its subdomains, or be listed intrusted_hosts). Ref GHSA-7pmw-jwvr-cq2x. (aba3b169) -
Host-mismatch response. The bare
die('Site Configuration Issue Detected. ...')that returned200 OKwith one line of plain text is replaced by a503 Service Unavailablewith a short HTML body that points the operator at the server error log. The diagnostic detail (configured siteurl, request Host) is written viaerror_log(), which previously sat after thedie()and never fired.The visible page intentionally does not echo the incoming
Host, the configured siteurl, or any admin URL. The diagnostic surface stays in the log, which already requires server access. (aba3b169)
Fixed
- Thumbnail rendering on PHP 8.
thumb.phpboots the framework directly withoutclass2.php, soE107_DEBUG_LEVELwas never defined for that request; the first call that opened a DB handle (typically when the SitePrefs disk cache was cold) hit a PHP 8+ fatal ine_db_pdo::__construct()and broke every thumbnail on the site. Now guarded withdefset(). Fixes #5664. (59aef4f1) - Thumbnail database credentials. With the
E107_DEBUG_LEVELfatal out of the way,thumb.phpthen failed withSQLSTATE[HY000] [2002] No such file or directorybecause its manual bootstrap chain never populated the MySQL config the PDO connector reads. The bootstrap now routes throughe107::initCore()(the same callclass2.phpuses), so credentials are set before the first DB call. Follow-up to #5664 / #5665. (02a79729) - Forgot-password page on v1-style themes.
fpw.phpfataled withUndefined constant LAN_112when the active theme had notheme.xml(the legacy theme path usese107_core/templates/legacy/fpw_template.php, which still references the old constant). The BC shim that mappedLAN_112→LAN_FPW22only fired in the members-only branch; it now fires before every downstream template require, regardless of branch. Fixes #5653. (d9725b91) - Other legacy templates. Any legacy core template under
e107_core/templates/legacy/that referenced a dropped v1.xLAN_*constant could fatal on PHP 8 with a single missed reference.e107::predefineLegacyLans()now tokenises each legacy template before it loads and auto-defines any missingLAN_*with its own name as a value, emitting anE_USER_WARNINGper auto-define so the maintainer trail stays visible. Wired into the six legacy require sites (fpw.php×2,search.php,signup.php,user.php,usersettings.php). Refs #5653. (b1290139) - Admin navigation icons and user-handler permissions on PHP 8.
sitelinks_class::setIconArray()built the admin nav map from ~40E_32_*constants anduser_handler::$core_permsreferenced dozens ofADLAN_*/ADMSLAN_*/E_16_*/E_32_*entries, all loaded lazily by the admin language file as bare reads. PHP 8 promotes bare reads of undefined constants to fatalErrors, so any caller that hit these before the admin language file loaded crashed. Both sites are now wrapped indefset()so the undefined case returns the empty default. (0635801a) - FAQ plugin cron registration on PHP 8.
e107_plugins/faqs/e_cron.phpreferencedLANA_FAQ_CRON_1,LANA_FAQ_CRON_2, andLAN_AUTOMATIONat admin cron-registration time, which runs beforeEnglish_admin.phpis loaded. PHP 8 turned the bareword fallback into a fatal; the registration path now usesdefset(). (21f7b584) strftime()deprecation on PHP 8.1+.StrptimeTrait::buildMonthArrays()called PHP'sstrftime()to localise month names. PHP 8.1 deprecated the function and PHP 9 will remove it, so the@-suppressed call still landed inerror_log. Both calls are now routed through theeShims::strftime()polyfill that already exists in the tree. (295ce2a1)
For Developers
Added
-
e107::predefineLegacyLans($path)token-scan safety net for legacy templates. Tokenises the requested template, finds bareLAN_*token references (skipping function/method/class/static contexts and call sites), anddefine()s any that are still missing with their own name as value. Token extraction is cached onhash_file('sha256', $path)keyed entries (APCu when available, otherwise a file undere_CACHE); a process-local memo short-circuits repeat resolutions. Warm-cache cost is roughly 6 µs vs the ~4 µs baseline.Wired into
fpw.php,search.php,signup.php,user.php, andusersettings.php. The wrappers call it immediately before the existingrequire/includeso caller-scope template variables ($FPW_TABLE,$SIGNUP_BODY, etc.) remain assignable. Refs #5653. (b1290139) -
trusted_hostsSitePref plumbing. A newe107::isAllowedHost()private helper composes the allow-list fromparse_url(siteurl)['host']plus the entries saved intrusted_hosts. The pref reads as a newline-separated list; the saver normalises (scheme/path strip, case-fold dedup) before writing back. (c2bb246b) -
Docker-based parallel test environments.
e107_tests/bin/e107-testsis a new CLI that spins up an isolated PHP + Apache + MySQL stack per worktree (up | down | reset | clean | install | urls | status | logs | shell | db-shell | exec | run | list). Each worktree + matrix combo gets a deterministic compose project name derived from the worktree path, so parallel sessions never collide on container names, networks, volumes, or host ports. A newconfig.docker.ymllayer slots into the existing config cascade (sample→yml→docker→local).Existing deployers (
local,sftp,cpanel,none) and the CI workflows are untouched. (9b5f40ea) -
Test coverage.
resize_handlerTestexercises the ImageMagick branch ofresize_image()with three command-substitution payloads and asserts no marker file is created and noid-style output leaks into a filename.e107HostValidationTestcovers the case-fold, www-strip, and port-strip behaviour ofe107::isAllowedHost()plustrusted_hostscomposition.e107RequireLegacyTemplateTestcovers the tokeniser context filtering, define/warn behaviour, scope preservation, missing-file return value, and the #5653 regression case. (794a179f, c2bb246b, b1290139)
Changed
-
language::bcDefs()no-argument default expanded. The boot-time call fromclass2.php:590previously defined onlyLAN_180 → LAN_SEARCH. Legacy templates that referenced any other dropped v1.x constant whose replacement happens to live inEnglish/English.phpstill fataled on PHP 8. The default now covers ~20 boot-resolvable aliases: generic actions (LAN_406/LAN_419/LAN_435), the v1 download prefix (LAN_dl_7..LAN_dl_35), and a defined-as-empty group for dropped-without-replacement constants.Conflict policy: where the same legacy constant had divergent mappings across per-entrypoint shims (
LAN_7..LAN_10,LAN_112,LAN_122, etc.) the global default deliberately omits them and per-entrypoint shims remain authoritative. Mappings whose replacement lives in a lazylan_*.phpcannot be resolved at boot (defined()returnsfalseand the entry silently no-ops); those are still handled by per-entrypointlanguage::bcDefs()calls after the relevante107::coreLan(). Refs #5653. (d2ef6b10) -
Host comparison helper. A new
e107::normaliseHost()lowercases, strips a trailing:port, and strips a leadingwww.before comparison. Plugins that previously did their ownHost-header guards should switch toe107::isAllowedHost()so thetrusted_hostsallow-list composes correctly. (aba3b169) -
resize_image()shell escaping. Theconvertcommand line now passes the destination throughescapeshellarg()and casts the integer geometry/quality args. If you maintain a fork or callresize_image()directly from a plugin, no migration is required, but any caller that previously relied on quoting the destination itself can drop that quoting. Ref GHSA-3j33-c9v4-4p42. (794a179f)
Fixed
-
thumb.phpbootstrap. The manual bootstrap chain (prepare_request/setDirs/set_constants/ ...) is replaced bye107::initCore()fed the samemySQL-prefixed$sql_infocompact()arrayclass2.phppasses.Note the v2.3.x
e107::_init()does not translate keys the way master'se107::setMySQLConfig()does, so the array must go in prefixed. The master-stylestr_replace('mySQL', '', $k)translation breaks v2.3.x becausee_db_pdostill reads$config['mySQLserver']etc. Follow-up to #5664 / #5665. (02a79729) -
submitnews.phptitle slug. The slug used to build the destination filename for resize is now confined to[A-Za-z0-9_]before reachingresize_image(), so shell metacharacters never escape the filter even if a future caller relaxes the filename quoting. Ref GHSA-3j33-c9v4-4p42. (794a179f) -
resize_handlerTestteardown sentinel.tearDown()ran even whensetUp()had short-circuited viamarkTestSkipped()(CI images without ImageMagick); in that case$savedPref === nulltook theunset($GLOBALS['pref'])branch and wiped the global pref array for every following test in the shuffled unit-suite run. AprefMutatedsentinel now flips true only after_before()mutates$pref, and_after()bails out early otherwise.Locally invisible because ImageMagick was usually installed and the early-skip branch wasn't taken. (8cf19729)
-
CI on the legacy PHP cells.
actions/checkout@v3was reclassified to a Node 20 action, which requires glibc 2.27+; the officialphp:5.6/php:7.0images are on Debian 9 (glibc 2.24) and the action errors before its main logic. The two legacy cells now use an inlinegit fetch+git checkoutagainst the run SHA.The
php:5.6×mysql:8.0andphp:7.0×mysql:8.0combinations have also been dropped viamatrix.exclude. Mysql:8 starts withcharacter-set-server=utf8mb4by default and the PDO driver in those PHP versions doesn't recognise the charset, failing the connection handshake before any test runs. (d024d205, 756dc92c) -
Composer audit no longer blocks resolution. Composer 2.9.x refuses to resolve package versions affected by a Packagist security advisory at install time. Every
twig/twigbetween v1.28 and v3.20 carries at least one advisory, leaving v3.26.0 as the only resolution candidate; v3.26.0 requires PHP 8.1+, so the PHP 7.4 cell of the unit-test matrix failedcomposer update. The test harness is dev-only and never ships with a release, so the audit's resolution-time block is now disabled viaconfig.audit.block-insecure: false.composer auditstill runs after install and reports any advisories. (46351d1a) -
Matrix CI design restored. The "Collapse 5×5 matrix into one host-orchestrated job" experiment that landed during the v2.3.5 cycle was reverted: single jobs ran ~20 minutes end-to-end vs ~5 minutes per cell under master's parallel matrix, and exhibited intermittent docker / mysql container startup races at the per-cell DB pre-create step. v2.3.x CI is back to the matrix layout that mirrors master, with the legacy PHP cells extended via the inline-checkout and matrix.exclude pair above. (da47684c)
-
language::bcDefs()graveyard collisions on v2.3.x. Pre-definingLAN_199,LAN_406, andLAN_419at boot collided with v2.3.x's lazylan_search.phpandlan_upload.php(which still usedefine(); master converted them to array form in #5465). PHPUnit'sconvertWarningsToExceptions=trueescalated the "Constant already defined" warning and aborted mid-load. Those three entries are dropped on this branch; the lazy LAN files remain authoritative. (f1b4bf27)