Download the PHP package sibidharan/zealphp without Composer
On this page you can find all versions of the php package sibidharan/zealphp. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download sibidharan/zealphp
More information about sibidharan/zealphp
Files in sibidharan/zealphp
Package zealphp
Short Description Coroutine-native PHP framework on OpenSwoole — async HTTP, WebSocket, streaming, and real-time applications.
License MIT
Homepage https://php.zeal.ninja
Informations about the package zealphp
ZealPHP — A PHP HTTP Server (built on OpenSwoole)
ZealPHP runs PHP as the HTTP server itself — not a CGI worker behind one. Built on OpenSwoole, it ships HTTP, WebSocket, SSE, coroutines, shared memory, timers, and task workers as first-class primitives because the server stays alive between requests. Existing PHP code runs unchanged via ext-zealphp function overrides; new features go async without a separate Node or Go service. Alpha — see stability note below.
Homepage: https://php.zeal.ninja
Running php app.php serves the same docs site locally. Set ZEALPHP_SITE_URL if you want the rendered example URLs to point somewhere else.
Changelog: CRITIC.md
PHP-FPM vs ZealPHP
| PHP-FPM | ZealPHP | |
|---|---|---|
| Process model | Request-per-process | Long-running server |
| WebSocket server | — | Built-in |
| Server-Sent Events | Workaround | Native |
| In-memory state across requests | — | Shared memory (Store) |
| Coroutines | — | OpenSwoole native |
| Background timers | — | App::tick() |
| Needs Node.js for realtime | Usually | No |
Try it: ~130 lines of PHP, no database, no Node.js.
Features
| Feature | Details |
|---|---|
| Async coroutines | go() + Channel — thousands of concurrent requests per worker |
| SSR streaming | Generator yield, $response->stream(), $response->sse() — like React's renderToPipeableStream |
| WebSocket | App::ws($path, $onMessage, $onOpen, $onClose) — rooms, auth, binary, heartbeat |
| Pluggable Store/Counter | Store::defaultBackend(Store::BACKEND_REDIS) (or ZEALPHP_STORE_BACKEND=redis) flips storage from local OpenSwoole\Table/Atomic to Redis/Valkey with zero handler changes — cross-node shared state + persistence with one line. Tracked + TTL modes, per-worker coroutine pool, Lua-backed Counter::compareAndSet. |
| Cross-node messaging | Store::publish($ch, $payload) + App::subscribe($ch, $handler) for fire-and-forget pub/sub (cross-worker AND cross-host). Store::publishReliable($stream, $payload) + App::subscribeReliable($stream, $handler) for Streams-backed at-least-once delivery via consumer groups. The cross-server WebSocket routing pattern (owner-of-fd pushes; Redis routes to owner) lights up end-to-end. Driver choice (both validated in v0.2.40): Both phpredis (preferred when ext-redis is loaded) and predis SUBSCRIBE loops yield correctly under OpenSwoole\Runtime::HOOK_ALL — the production default in coroutine mode. phpredis is ~2× faster on hot CRUD; pick it when you can. One nuance: phpredis SUBSCRIBE blocks the worker WITHOUT HOOK_ALL — if you disabled HOOK_ALL explicitly, force ZEALPHP_REDIS_PREFER=predis for subscribers or re-enable HOOK_ALL. See /store#pubsub. |
| Dynamic routing | route(), nsRoute(), nsPathRoute(), patternRoute() with reflection-based parameter injection |
| Middleware | PSR-15 stack — 30+ built-ins (CORS, ETag, Range, Compression, SessionStart, IniIsolation, Charset, CacheControl, Expires, Header, BasicAuth, IpAccess, RateLimit, ConcurrencyLimit, BlockPhpExt, MimeType, BodyRewrite, HostRouter, BodySizeLimit, Csrf, Redirect, Scoped, MergeSlashes, Referer, RequestHeader, Return, SetEnvIf, ContentEncoding, ContentLanguage, HealthCheck) — full Apache mod_rewrite / mod_headers / mod_expires and nginx limit_req / auth_basic parity — see the middleware reference for the full list |
| HTTP/1.1 compliance | HEAD, OPTIONS, 301/302/307/308 redirects, Cookie SameSite, ETag, OpenSwoole compression |
| Shared memory | Store (OpenSwoole\Table) + Counter (OpenSwoole\Atomic) — cross-worker state |
| Timers | App::tick(), App::after(), App::onWorkerStart() — per-worker recurring tasks |
| ZealAPI | File-based REST: drop api/device/list.php → /api/device/list works automatically |
| Templating | Nested App::render() / App::renderToString() — single _master.php, component-based |
| Sessions | All session_*() functions overridden via ext-zealphp — coroutine-safe, per-request isolation |
| Unit tests | PHPUnit 11 — extensive unit and integration test suites, all green |
| Benchmarks | OpenSwoole-powered concurrency with a modular scripts/bench.sh runner for wrk/ab sweeps through c=1000 |
Performance: 117k req/s text · 106k JSON · 50k templated with 4 HTTP workers under the full PSR-15 middleware stack, 0 failures across 150k requests. ZealPHP retains ~82% of OpenSwoole's raw throughput with the framework on top; numbers vary by workload, payload, and hardware.
Reproduce in 60s:
./scripts/bench_vs_express.sh. Full methodology, latency percentiles, concurrency sweep, and caveats: PERF.md. Stability: Alpha (v0.2.x). API may change between minor versions until v1.0. Pin to a specific version in production.Common Apache + nginx behavior coverage (v0.2.21). ZealPHP ships built-in middlewares and server-level setters for the common
.htaccess/nginx.confpatterns used by traditional PHP apps — rewrite-style routing, headers, expiry/cache rules, basic auth, IP access, rate limits, MIME types, request limits. This is coverage for migration use cases, not a byte-for-byte server replacement. 12 new middlewares (HeaderMiddleware,BasicAuthMiddleware,RateLimitMiddleware,CharsetMiddleware,CacheControlMiddleware,ExpiresMiddleware,IpAccessMiddleware,ConcurrencyLimitMiddleware,BlockPhpExtMiddleware,MimeTypeMiddleware,BodyRewriteMiddleware,HostRouterMiddleware) and 8 new configurables ($server_admin,$canonical_name,$trusted_proxies+App::clientIp(),$access_log_format,LimitRequestFieldsfamily,$strip_trailing_slash,App::tryInclude()) landed in v0.2.21. See the middleware reference and the legacy-apps coverage matrix for the full story.
Why ZealPHP?
The architectural shift: PHP becomes the HTTP server. The migration story is the on-ramp; the destination is "your existing PHP code, plus WebSockets/SSE/coroutines/shared memory/timers, all in one PHP application server."
PHP powers ~71% of the web (W3Techs), but the default request-per-process model (PHP-FPM, mod_php) keeps the interpreter warm yet discards request-local state, and gives PHP no native way to hold a persistent connection — so WebSocket/SSE features land in separate Node/Go sidecar processes. ZealPHP runs on OpenSwoole — a long-lived PHP server with native coroutines — and adds a framework layer that:
- Accepts many traditional PHP patterns unchanged (compatibility mode). Drop
.phpfiles inpublic/.session_start(),header(),$_GET,$_POST,setcookie(),echoall route through ext-zealphp overrides into per-request state. Many WordPress sites run through the CGI worker bridge — see zealphp-wordpress for the showcase and documented limits. Compatibility is a migration on-ramp, not a guarantee that every PHP application is safe to drop in without an audit. - Adds async primitives when you want them.
go(),Channel, WebSocket, SSE, shared memory (Store/Counter), timers, task workers — all framework-native, no extra services. - Lets you migrate file by file. Start with fallback routing on day one; opt into coroutine mode when you're ready. No big-bang rewrite.
vs other ways to make PHP async
- vs PHP-FPM / mod_php — FPM keeps workers warm but discards request-local memory and treats PHP as a CGI worker, not the HTTP server. ZealPHP IS the HTTP server: caches survive across requests, and SSE/WebSocket connections are much cheaper to keep open than under request-per-process PHP (real capacity still depends on file descriptors, heartbeat policy, and OS tuning).
- vs Laravel Octane — Octane wraps Swoole inside a Laravel kernel. ZealPHP is framework-agnostic and exposes the runtime primitives directly. If you're on Laravel and want it faster, use Octane.
- vs FrankenPHP / RoadRunner — Go servers fronting PHP. ZealPHP runs native PHP coroutines on OpenSwoole — no Go process in between.
- vs ReactPHP / AMPHP — Library collections you wire together. ZealPHP is the integrated framework on top.
- vs raw Swoole / OpenSwoole — ZealPHP adds routing, PSR-15 middleware, templates, session overrides, and the legacy bridge so you don't write
onRequesthandlers by hand. - vs Node.js — Different language and ecosystem; not the same trade-off space. If you're already in JS, stay in JS. ZealPHP exists for teams that want OpenSwoole-style concurrency without leaving PHP, or that need to bring a PHP codebase along.
Quick Start
Docker (fastest path — no system setup)
Composer (requires PHP 8.3+, OpenSwoole, ext-zealphp)
Architecture
The ext-zealphp function overrides are the framework's load-bearing trick: legacy PHP code calls session_start() or header() unchanged, but the calls route to per-coroutine state instead of mutating process globals. This lets many traditional PHP patterns — including unmodified WordPress in compatibility mode — run on OpenSwoole's coroutine runtime, with documented limits where the legacy bridge can't fully match Apache's request isolation.
More detail in docs/runtime-architecture.md.
Migrate an Existing PHP App
ZealPHP can run your existing PHP codebase on a high-performance async runtime — session_start(), header(), $_GET, $_POST all work unchanged:
Now your WordPress, Drupal, or custom PHP app runs on OpenSwoole — persistent connections, no cold starts, WebSocket and streaming available when you're ready. ZealPHP's file-execution family — App::render() / App::renderToString() / App::renderStream() / App::include() — share a single core that runs the file, captures its output, and applies the universal return contract. Need htmx-style swap targets without separate partial files? App::fragment() (v0.2.24) marks named regions inline so the same App::render() call serves either the full page or just one region — see Template fragments. App::includeFile() is the deprecated alias for App::include() and still works. See the legacy apps page for the 12 Apache rewrite recipes and the full .htaccess / nginx.conf coverage matrices.
Background Run
Run ZealPHP detached from the terminal:
PID file lives at /tmp/zealphp/zealphp_{port}.pid (one per port — multiple
apps on different ports are supported). Logs go to /tmp/zealphp/:
server.log, access.log, debug.log, zlog.log. php app.php logs tails
all four; add --access, --debug, --server, or --zlog to filter.
If a server is already running on the same port, start prints the existing
PID and exits cleanly instead of crashing. restart stops then starts using
the same defaults. Target a specific instance with -p PORT on
stop/status/restart.
scripts/zealphp.sh is an optional shell wrapper around the same commands.
Docker Benchmark
Run the benchmark in Docker with PHP, OpenSwoole, ext-zealphp, Composer deps, and wrk
inside the image:
Results are written to bench/results/ on the host.
On Docker Desktop for Mac, set Resources -> CPU limit to 16 if you want the
container to use all 16 cores.
For a quad-core ZealPHP vs Node.js comparison:
Set ZEALPHP_BENCH_MODE=1 to skip the demo middleware and session file I/O on
the benchmark path. The sample auth/validation middleware is opt-in via
ZEALPHP_DEMO_MIDDLEWARE=1.
Set ZEALPHP_LOG_DIR=/tmp/zealphp to send debug.log, access.log, and
zlog.log there, and keep ZEALPHP_LOG_ASYNC=1 so request logging is queued
off the hot path. Use ZEALPHP_DEBUG_LOG=0 and ZEALPHP_ACCESS_LOG=0 for
quiet runs.
If /tmp/zealphp is not writable, ZealPHP falls back to a writable local log
directory.
Installation
1. Install OpenSwoole
Add to /etc/php/8.3/cli/conf.d/99-zealphp.ini:
2. Install ext-zealphp
3. Verify
Or use the automated setup:
Testing
Unit suites (tests/Unit/): StoreTest, CounterTest, BuildParamMapTest, RoutePatternTest
Integration suites (tests/Integration/): RoutingTest, HttpFeaturesTest, MiddlewareTest, StreamingTest
Make targets
Common dev tasks are wrapped in a Makefile — run make (or make help) to list them. They're thin wrappers over the composer / vendor/bin/* / php app.php / scripts/*.sh commands documented above, so they never drift.
Core Concepts
Parameter Injection
ZealPHP uses reflection (cached at route registration, zero overhead per request) to inject handler arguments by name:
Middleware
Store & Counter (cross-worker shared memory)
Timers (per-worker)
Design Principles
Coroutine mode (recommended): App::superglobals(false) enables OpenSwoole\Runtime::HOOK_ALL so all PHP I/O (file, curl, PDO, sleep) yields the event loop automatically. Each request runs in its own coroutine with isolated RequestContext::instance() state (G remains as a class_alias for RequestContext since v0.2.6 — both names resolve to the same class). This is the default for new scaffolds since v0.2.4.
Superglobals mode (legacy compatibility): App::superglobals(true) disables coroutines in the main thread — $_GET, $_POST, $_SESSION work safely because only one request runs at a time per worker. Use this when migrating existing apps incrementally. Implicit file routes for legacy code run through the CGI bridge (App::include()) via a pre-spawned subprocess pool (cgiMode('pool'), entry script src/pool_worker.php, ~1–3 ms warm, the default) so blocking PHP runs in a child process with its own arena. cgiMode('proc') opts into a fresh proc_open subprocess per request (~30–50 ms cold, entry script src/cgi_worker.php) for the rare case that demands fully fresh-process semantics.
coprocess / coproc: Available in superglobals mode — spawns a child process for background async work. Not needed in coroutine mode (use go() directly).
Lifecycle modes — one-call presets: App::mode(string) sets both the superglobals strategy and the isolation strategy in one call. Four presets:
| Preset | Use for |
|---|---|
App::mode(App::MODE_COROUTINE) |
Modern ZealPHP apps — recommended default |
App::mode(App::MODE_LEGACY_CGI) |
Unmodified WordPress/Drupal — pure require_once apps |
App::mode(App::MODE_COROUTINE_LEGACY) |
Legacy request-style PHP run concurrently — per-coroutine isolation of $_GET/$_POST/$_SESSION, $GLOBALS, function statics, require_once, silent re-declaration. define() isolation is opt-in via App::defineIsolation(true), not part of the preset. Requires ext-zealphp. |
App::mode(App::MODE_MIXED) |
Symfony/Laravel bridge — real $_SESSION, sequential, no CGI fork cost |
The fine-grained setters (App::superglobals(), App::isolation(), App::enableCoroutine(), etc.) remain available for custom combinations. See the lifecycle modes reference for the full matrix.
ext-zealphp overrides: header(), setcookie(), all session_*() functions are permanently replaced at startup via ext-zealphp overrides. This makes existing PHP code work unchanged inside the long-running OpenSwoole process.
Publishing Releases
- Update
CHANGELOG.mdwith the new version and changes. - Run
composer validateand confirm tests pass. -
Tag both
zealphpandzealphp-projectwith the same version: - Trigger Packagist webhook for both packages.
Common Errors
OpenSwoole not installed:
→ Install OpenSwoole via PECL and add extension=openswoole.so to php.ini.
ext-zealphp not installed:
→ pie install sibidharan/ext-zealphp and add extension=zealphp.so to php.ini. Or build from source — see the install section above.
IDE autocompletion:
Add to VS Code settings.json:
Any and all contributions are welcome ❤️
All versions of zealphp with dependencies
ext-openswoole Version >=22.0
openswoole/core Version ^22.1.5
openswoole/ide-helper Version ^22.0.1
psr/http-message Version ^1.1
psr/simple-cache Version ^3.0
psr/log Version ^3.0
psr/http-factory Version ^1.1
psr/http-client Version ^1.0
league/commonmark Version ^2.8