druvu-lib-web

Write your pages in PHP. Run them on the JVM. A small Java web framework on Jetty 12 whose templates are real PHP 8, executed by Java. No PHP runtime, no FPM, no mod_php.

One thing is deliberately different from PHP: output is HTML-escaped by default, and raw() is the opt-out. Forgetting is safe. Published to GitHub Packages, which needs a one-time token to read. See Install.

View on GitHub


Try it

Write the page:

<!-- dashboard.php -->
<?php require 'includes/header.php'; ?>
<h1>Welcome, <?= $customer->name ?></h1>

<ul>
<?php foreach ($orders as $order): ?>
  <li><?= $order->reference ?> — <?= number_format($order->total, 2) ?></li>
<?php endforeach; ?>
</ul>

Give it something to show:

public class DashboardHandler implements HttpHandler {
    @Override
    public void handle(HttpRequest request, HttpResponse response) {
        request.setAttribute("customer", customer);  // becomes $customer
        request.setAttribute("orders", orders);      // becomes $orders
    }
}

Start the server:

WebBoot boot = new WebBoot(WebConfig.builder()
    .port(8080)
    .route(Route.forEveryone(DashboardHandler.class))
    .authConfig(AuthConfig.builder()
        .basicAuth()
        .user("admin", "secret")
        .build())
    .build());

boot.start("/myapp");
// Server running at http://localhost:8080/myapp/dashboard

What you get

  • Real PHP 8 in the templates. Variables, every control structure, string interpolation, heredocs, includes, arrow functions and 115 standard functions. Whole templates are matched against PHP’s own output, byte for byte.
  • Routing by convention. DashboardHandler answers /dashboard. A handler that does not commit a response falls through to the matching template; response.commit("application/json", json) answers JSON instead.
  • Sign-in built in. Basic auth with inline users, OpenID Connect through one provider (no password is ever stored), bearer tokens for machines. Permissions per route, checked before the handler runs.
  • WebSocket with JSON messages and session management.
  • WebJars. webjar('bootstrap.min.css') finds the file, with no version in the template.
  • Template engines are plugins, discovered via ServiceLoader. Drop a jar, it is picked up.

Install (GitHub Packages)

Java 25. GitHub Packages needs Maven authentication even for a public package. Once per machine: a token with the read:packages scope and a server entry in ~/.m2/settings.xml:

<servers>
  <server>
    <id>github</id>
    <username>YOUR_GITHUB_USERNAME</username>
    <password>YOUR_GITHUB_TOKEN</password>
  </server>
</servers>

Then in the project, the repository, the core, and the PHP engine at runtime:

<repositories>
    <repository>
        <id>github</id>
        <url>https://maven.pkg.github.com/DenissLarka/druvu-lib-web</url>
    </repository>
</repositories>
<dependency>
    <groupId>com.druvu</groupId>
    <artifactId>druvu-lib-web-core</artifactId>
    <version>3.0.0</version>
</dependency>
<!-- PHP template engine (loaded automatically via ServiceLoader) -->
<dependency>
    <groupId>com.druvu</groupId>
    <artifactId>druvu-lib-web-php</artifactId>
    <version>3.0.0</version>
    <scope>runtime</scope>
</dependency>

The full reference, the PHP dialect, the handler and WebSocket contracts, is the README.


Something it almost does?

Open an issue, or write to me. If it is small and useful to more than you, I will often just build it.

Apache License 2.0.


Back to top

Copyright © 2026 druvu.com. All rights reserved.

This site uses Just the Docs, a documentation theme for Jekyll.