Tags

Tags give the ability to mark specific points in history as being important
  • v0.2.43

    Release v0.2.43
    
    - fix(session): persist sessions in CGI isolation mode (#108) — pool worker now flushes $_SESSION between dispatches; SessionManager skips its lifecycle when superglobals(true) + processIsolation(true) (subprocess owns sessions); App::mintCgiSession() emits Set-Cookie on first-visit since PHP's session module can't reach userspace setcookie() under uopz.
  • v0.2.42

    Release v0.2.42
    
    - Fix #103: variadic-defensive App::dispatchTaskCallback() for OpenSwoole
      22.x's two task-handler signatures (2-arg coroutine + 4-arg legacy).
      Prod workers no longer crash with ArgumentCountError under default
      task_enable_coroutine => true. Pinned by 10 unit tests.
    - Acknowledge #104: sibling-package zealphp-mongodb v0.2.8-v0.2.11
      (BSONDocument drop-in, MongoDB\Driver\* polyfills, pass-by-ref fixes).
      No framework change; documented upgrade path in CHANGELOG.
    
    Also carries the intended v0.2.41 release content (FCGI worker pool
    default, WP-on-proc regression fix, ZealAPI helpers) — v0.2.41 was
    mis-tagged on Packagist at orphan commit 0372c3a. Skip v0.2.41;
    composer require sibidharan/zealphp:^0.2.42 if already installed.
  • v0.2.41

    Release v0.2.41
    
    - ZealPHP-native FCGI-style worker pool — cgiMode('pool') is now the
      framework default. CGI bridge per-request cost drops ~30–50 ms (proc)
      to ~1–3 ms (pool). cgiMode('fork') removed entirely.
    - FPM-style $GLOBALS snapshot/restore in pool_worker.php.
    - WordPress on cgiMode('proc') regression fix (issue #18): autoload
      gated behind opt-in App::cgiSubprocessAutoload(true), default off
      restores v0.2.0 zero-overhead subprocess start.
    - ZealAPI helpers upstreamed from labs-dashboard-web (PR #100):
      resolveClubParam(), failAs(Throwable), json() made public.
  • v0.2.40

    Release v0.2.40
    
    Production hardening + Memcached + federated WebSocket rooms.
    
    Highlights
    - Production hardening pass on the Redis backend surface — closed 3
      critical (FD-reuse race in WSRouter, HMAC-signed L1 invalidations,
      rediss:// TLS) + 10 medium gaps. Default behaviour preserved across
      all 13 fixes.
    - Memcached backend for Store + Counter (Store::BACKEND_MEMCACHED,
      Counter::BACKEND_MEMCACHED) with ZEALPHP_MEMCACHED_SERVERS env var
      + array config; phpredis + predis driver validated for SUBSCRIBE
      under HOOK_ALL.
    - Federated WebSocket Rooms (P1.1 of v0.3.0 roadmap, landed early) —
      WSRouter::room(name): Room with first-class join/leave/push/onMessage/
      onPresence + cluster-wide membership via shared Store table + one
      PSUBSCRIBE pattern subscriber per worker.
    - Three-backend Store facade — Store::BACKEND_TABLE / BACKEND_REDIS /
      BACKEND_TIERED, plus Cache::getOrCompute read-through with null
      sentinel.
    - v0.3.0 early helpers — App::parallel / parallelLimit, App::onSignal,
      App::stats, HTTP::get/post/put/delete, App::addProcess for sidecars.
    - Real end-to-end async integration tests for pub/sub + streams
      delivery (RedisPubSubFederationTest) + redis-pubsub coverage pass.
    - Fixed route/demo_rooms.php deferring WSRouter::init to onWorkerStart
      (would crash production deploys with ZEALPHP_STORE_BACKEND=redis).
    
    CI: every required check green, codecov/patch passed at 79.03%.
  • v0.2.39

    Release v0.2.39 — pluggable Store/Counter backends
    
    Phase 1 of the pluggable-backend program. `Store` and `Counter` now
    delegate to backend instances behind their existing static/instance APIs.
    `OpenSwoole\\Table` / `OpenSwoole\\Atomic` remain the default (nanosecond
    hot path); flip to Redis/Valkey for cross-node shared state with one line
    in app.php (`Store::defaultBackend(Store::BACKEND_REDIS)`) or the
    `ZEALPHP_STORE_BACKEND=redis` env var. Every existing handler call site
    keeps working unchanged.
    
    Pub/sub + Streams primitives (`Store::publish` / `App::onPubSub` /
    `Store::publishReliable` / `App::onReliableMessage`) ship in this release
    backed by RedisPubSub + RedisStreams lifecycle classes. Phase 3 pub/sub
    design empirically de-risked via three committed spikes (in-process,
    cross-process, cross-host @ 0.53 ms median via wireguard).
    
    Tagged retroactively at d854b99 (the 'complete v0.2.39 version-ref bumps'
    commit) — the v0.2.39 content was authored but never tagged when work
    moved on to v0.2.40. Master branch is behind d854b99; the v0.2.40 release
    on top of v0.2.39 brings everything to master via PR #87.
    
    Full notes: CHANGELOG.md [0.2.39] section (kept verbatim within the
    v0.2.40 collapsed entry).
  • v0.2.38

    Release v0.2.38 — Apache + nginx parity wave
    
    Security:
    - referer DNS-label wildcard (closes example.evil.com over-match)
    - symlink escape via static serving (realpath docroot containment)
    - mod_expires no longer caches 4xx/5xx
    - double-encoded traversal (%252e%252e -> 400)
    - multi-range DoS cap (CVE-2011-3192 class)
    - explicit plaintext-htpasswd rejection + DES salt alphabet fix
    - error responses no longer leak prior handler headers
    
    Added:
    - ConditionalRequest evaluator (RFC 9110 If-Match/Unmod/None-Match/Mod-Since precedence + 412)
    - MimeResolver (multi-suffix Content-Type/Encoding/Language a la mod_mime)
    - ContentEncoding/ContentLanguage middleware
    - per-key ConcurrencyLimit (Store-backed, proxy-aware) + dry-run + configurable status
    - RateLimit burst/nodelay/dry-run/configurable-status, App::clientIp() keying
    - HostRouter trailing-wildcard + regex server_name + Host-400, IPv6 host parse
    - HeaderMiddleware nginx-style status-conditional add_header + always opt-out
    - Range If-Range HTTP-date; sendFile multi-range (206 multipart)
    - ExpiresMiddleware dual-header + M-base + error-suppress + clamp
    - Two source-diff audit docs: docs/apache-parity-audit.md, docs/nginx-parity-audit.md
    
    Changed:
    - HeaderMiddleware default = status-conditional (mild BC; per-rule always to restore)
    - Compression Vary merges instead of overwriting, q=0 refused, weak-ETag on compress
    - Redirect QSA merges query with & when target has one
    - BodySizeLimit chunked enforcement + 0 = unlimited
    - App::$limit_request_fields enforced (400 on excess); STANDARDS.md adds OpenSwoole-governed surfaces
    
    Tests: 1962 unit, Infection covered-MSI 92% (gate 92), plain-MSI 90% (gate 88).
    PR #38.
  • v0.2.37

    Release v0.2.37
    
    - BasicAuth APR1 (apr_md5) digest fix: byte-reversed encoding could never verify a real htpasswd -m hash; now pinned against Apache htpasswd/openssl oracles
    - Infection covered-MSI 65% -> 95% (1680/1763 killed; 83 survivors all provably-equivalent, catalogued in STANDARDS.md); gate ratcheted to 88/92
    - Apache httpd core-logic diff + non-support register (ProxyPass/TLS/WebDAV/CGI/mod_rewrite/.htaccess/...)
    - Runnable HTTP fuzz harnesses: radamsa (500 muts, 0 hangs/0 leaks), gabbi (7/7), slowhttptest; wired into CI (fuzz.yml)
  • v0.2.36

    Release v0.2.36
    
    - 405 Method Not Allowed + Allow header (RFC 9110 §15.5.6); implicit document-root routes scoped to GET/POST (Apache static-handler parity)
    - Mutation Score Indicator badge in README, auto-refreshed from CI on master
    - Conformance: symlink-escape refusal + chunked-framing edge cases (extension/trailer/leading-zeros)
    - STANDARDS.md advanced-testing roadmap (Infection / http-garden / Radamsa / slowhttptest / Gabbi)
  • v0.2.35

    Release v0.2.35
    
    HTTP/1.1 + static-serving conformance:
    - RFC 9112 §3.2 Host enforcement: HTTP/1.1 without Host -> 400 (1.0 exempt).
    - StaticServingConformanceTest: traversal corpus confined to docroot, dotfiles
      never served, autoindex off, MIME + conditional 304.
    - Host-rule + response-splitting (header() CR/LF/NUL) conformance.
    - STANDARDS.md request-line/Host/static matrix + OpenSwoole deviation register.
  • v0.2.34

    Release v0.2.34
    
    Standards conformance + Apache/nginx parity:
    - Conformance suites: IANA status (exhaustive), RFC 6265 cookies, RFC 9110 IMF-date,
      HTTP/1.1 framing & request smuggling (RFC 9112 §6-§7), live traversal proof.
    - CI gates: 80% coverage floor (codecov), Infection mutation testing (minMsi 55 /
      covered 60), perf-regression smoke. STANDARDS.md catalogue.
    - Middleware: ScopedMiddleware, RequestHeaderMiddleware, MergeSlashesMiddleware,
      BodySizeLimitMiddleware, RefererMiddleware, ReturnMiddleware.
    - Fixes: #23 session pipe-format cross-server parity, #25 .php URLs 404 not 403.
  • v0.2.33

    Release v0.2.33
    
    Fixed:
    - #16 RedisSessionHandler is now coroutine-safe (one \Redis connection per
      coroutine instead of a shared socket) — resolves session corruption under
      concurrent/rapid sequential requests with a shared handler.
  • v0.2.32

    Release v0.2.32
    
    Apache/mod_php parity wave 2:
    - Built-in overrides: php_sapi_name, filter_input/filter_input_array, header_register_callback, error_log
    - $_SERVER completeness: GATEWAY_INTERFACE, REQUEST_SCHEME, HTTPS
    - Directive middleware: RedirectMiddleware (mod_alias), SetEnvIfMiddleware (mod_setenvif)
    - Config: ServerTokens (X-Powered-By), FileETag, default_mimetype
    Fixes:
    - #20 void return discarded buffered output
    - #21 unset($g->session[k]) not persisted through custom handler
  • v0.2.31

    Release v0.2.31
    
    - phpinfo() now renders styled HTML (Apache/mod_php parity) via ZealPHP\Diagnostics\PhpInfo + uopz override
    - App::onWorkerStop() per-worker shutdown hook
    - Fix #18: API routes keep DOCUMENT_ROOT at the web root (not /api); SCRIPT_NAME/PHP_SELF/SCRIPT_FILENAME parity
    - Fix #19: session_regenerate_id() is custom-handler-aware — migrates data + emits new-ID cookie (Redis/Valkey OAuth flows)
    - Test coverage ~29% -> ~80% combined; real WebSocket integration tests
  • v0.2.30

    Release v0.2.30 — full superglobal aliasing ($g->get IS $_GET in superglobals mode) + issue #17 CLI/CGI fixes
  • v0.2.29

    Release v0.2.29 — App::cgiMode('fork') warm-fork CGI bridge (~5x faster than proc_open, opt-in)
  • v0.2.28

    Release v0.2.28 — canonical compat/g.php dual-runtime shim + real FPM benchmarks (docs/tooling, no behaviour change)
  • v0.2.27

    Release v0.2.27 — superglobals(true) parity + drop-in LAMP Mixed-mode
    
    - $_GET/$_SESSION et al. populated per request in superglobals(true) mode
    - $g->session aliased to $_SESSION (same array)
    - Unsafe lifecycle combos throw at boot
    - examples/lamp-scaffold + SuperglobalsParityTest
    - Known issue: Symfony coroutine-mode session concurrency (use enableCoroutine(false))
  • v0.2.26

    Release v0.2.26
    
    Closes issue #15: narrow whitelist for session unserialize.
    
    v0.2.25 set allowed_classes => false in all session decode paths,
    converting stdClass (the most common session object shape — json_decode
    output, OAuth tokens, API profiles) to __PHP_Incomplete_Class and
    breaking real apps. v0.2.26 narrows the whitelist to ['stdClass']
    specifically — zero magic methods means no gadget chain — while keeping
    every other class refused.
    
    PHPStan level 10 clean. 385 unit + 147 integration tests pass.
  • v0.2.25

    Release v0.2.25
    
    Closes issue #13 with two complementary fixes:
    
    - Added: App::authChecker(?callable), adminChecker(?callable),
      usernameProvider(?callable) — apps wire ZealAPI's auth methods to
      their own session/auth state. Was hardcoded `return false;` in PR #10.
    
    - Fixed: session write/destroy now delegates to \SessionHandlerInterface
      when one is registered (PR #14). Redis-backed sessions actually
      persist now. Plus read-then-merge for the handler-write path to
      mitigate concurrent-request races on top-level session keys.
    
    Backwards-compatible — both fixes only change behaviour when the
    opt-in (authChecker registration / handler registration) is used.
    
    PHPStan level 10 clean. 383 unit + 147 integration tests pass.
  • v0.2.24

    Release v0.2.24
    
    - feat(fragment): App::fragment(name, fn) — htmx-essay template fragments.
      Mark named regions inside a template; the same App::render('page', args)
      call serves the full page (no selector) or just one region (selector
      passed via $args['fragment']). 5th member of the file-execution family
      alongside render / renderToString / renderStream / include. Honours the
      universal return contract (int=status / array=JSON / string=HTML /
      Generator=stream). Missing fragment → HTTP 404, no silent fallback.
    
    - fix(session): session_start() auto-emits Set-Cookie on first-time
      visitors (PR #12). Restores correct OAuth/redirect behaviour where a
      302 used to go out with no PHPSESSID and the next request started a
      fresh session.
    
    - fix(executeFile): HaltException catch no longer drops the buffered
      output when no explicit result was captured. echo "x"; throw new
      HaltException now correctly returns "x" as the body.
    
    Lessons:
    - /learn/htmx extended with "Template fragments — one file, two responses"
    - /learn/sessions extended with "First-visit cookie" section (PR #12)
    Live demo: /demo/fragments/contacts
    
    PHPStan level 10 clean. 362 unit + 147 integration tests pass.