PHP.GT

News & Updates

PHP.GT/Flux is ready to use

Published on by Greg Bowler

PHP.GT/Flux is now released as the small client-side library that gives server-rendered applications a fluid user experience, without asking us to stop writing normal HTML pages, forms, and links.

If we have a page that already works with ordinary browser behaviour, Flux can progressively enhance it. Forms still submit to the same PHP code. Links still point at real pages. The server still returns complete HTML documents. Flux simply makes the browser experience feel fluid by fetching those documents in the background and replacing the matching parts of the current page.

A note on the name

During development, this project was called Turbo. That name made sense within the context of WebEngine, but I dropped it in favour of the portmanteau of Fluid User Experience, Flux.

The web already had well-known Turbo projects, especially in the Hotwire ecosystem, and reusing the name would have caused confusion for developers, documentation, search results, package listings, and anyone trying to explain which Turbo they meant. So the name was dropped before release.

Flux fits the project better. It describes the feeling we want from server-rendered pages: the page can keep moving, updating, and responding, while the underlying application remains ordinary, readable, and proudly HTML-shaped.

You can start now

Flux is available to use today. It is shipped by default with PHP.GT/WebEngine applications, and it can also be used as a standalone browser library in any server-rendered project.

The first thing to try is a normal form:

<form method="post" data-flux="update">
	<button name="do" value="save" data-flux="submit">Save</button>
</form>

There is no new client-side state model hiding behind that button. It is still a form, still a POST request, and still your server-side code doing the real work.

Try the examples

If you have PHP installed, run php -S 0.0.0.0:8080 and visit http://localhost:8080/example in your browser.

The example/ directory shows the library in a real browser, from the tiny counter through to live updates, drag ordering, and link navigation. The link demo in example/04-links.php is a good one to poke at because it mixes full-page navigation with smaller card updates on the same page.

To run the browser examples through the test suite:

composer install
composer behat

The Behat wrapper starts a local PHP server, opens Chrome or Chromium headlessly, and checks that the examples behave as intended.

For the JavaScript unit tests:

npm test

Why Flux exists

Flux exists because server-rendered web applications are still excellent.

The web already gives us forms, links, history, accessibility, caching, URLs, and decades of shared understanding. The problem is not that those tools are old; the problem is that full-page refreshes can feel clunky when a user only changed one small part of the page.

Flux satisfies that middle ground. It keeps the application model simple enough for humans to reason about, while smoothing the experience for the person using the site. We do not need a bespoke JSON API for every button. We do not need to rebuild page state in two languages. We can keep serving HTML, then let Flux help the browser swap the right pieces into place.

That is the little trick: keep the web honest, but make it feel lovely.

WebEngine v5 is here!

Published on by Greg Bowler

WebEngine v5 is a substantial refactor of the framework’s core. If you’ve used previous versions, the philosophy will feel familiar and unchanged: start static-first, keep logic close to the URL it serves, and let the framework step aside as quickly as possible. What has changed in v5 is how much cleaner, more testable and more explicit the internals have become.

This release focuses on making the request-response lifecycle easier to reason about, improving support for non-HTML responses, and giving applications more control over redirects, errors and runtime behaviour. A lot of the work in this version is under the bonnet, but it should still be felt directly in day-to-day development.

A clearer application lifecycle

One of the biggest changes in v5 is the move away from the older middleware-centred lifecycle classes and towards a more explicit Application and Dispatcher flow.

Sidenote: PHP.GT is gradually moving away from PSR compatibility, and the drop of MiddlewareInterface was the first piece of the move. More on this in a later update.

All of this matters because the framework now has a much clearer path from incoming request to outgoing response:

  • The application starts in one obvious place.
  • Global protection, request creation and dispatch are handled in a predictable order.
  • Error responses are generated through the same dispatch pipeline.
  • The responsibilities of bootstrapping, routing, initialisation and rendering are much more clearly separated.

This kind of refactor does not add a flashy new API, but it does make WebEngine itself easier to maintain, test and extend. In practice, that means fewer hidden interactions and a core that is easier to trust.

Better support for different kinds of response

WebEngine has always treated the URL as the authority for application behaviour, and v5 pushes that idea further.

The default router now has proper support for non-HTML views, including a dedicated JSON view for API-style responses. HTML remains the default for regular pages, but the framework is now in a better position to treat other representations as first-class citizens instead of edge cases.

This is useful if your project serves a mixture of web pages and structured responses from the same application, because the framework’s internals are now much closer to how people actually build systems in practice.

File-driven redirects

Redirects have been reworked into their own focused part of the framework.

In v5, redirects can be defined in project-level files such as redirect.ini, redirect.csv or redirect.tsv, and are resolved before the rest of the page lifecycle begins. This makes redirects easier to audit and easier to hand over, especially when the people maintaining them are not the same people writing application code.

For teams, this is a small but important quality-of-life improvement. Nothing major to shout about, but something that removes annoying repetition on nearly all projects I’ve worked on.

More flexible error handling

Error handling has had a meaningful upgrade as part of the refactor.

WebEngine v5 introduces a more structured path for error responses, including support for custom error page directories and optional custom error scripts. Error pages are routed more deliberately, and development-mode behaviour is clearer when something goes wrong.

That gives you a better split between local debugging and production behaviour:

  • In development, errors can expose more context to help you fix the problem quickly.
  • In production, responses can remain cleaner and more controlled.
  • Missing error pages fall back more gracefully instead of collapsing the whole request.

This is the one feature that has been lacking he most in v4, and the kind of feature that helps improve development experience when something goes wrong and we would rather not be thinking about framework internals.

Improved request normalisation and configuration

There are also several practical improvements to application behaviour and configuration.

Trailing slash normalisation is now handled explicitly, logging has gained more options, session defaults are more sensible, and the framework’s configuration surface is more in line with real deployment needs. There is also support for lightweight project bootstrapping and teardown through optional setup.php and teardown.php files.

None of these changes are especially dramatic on their own, but together they make the framework more adaptable without pulling it away from its minimal approach. The whole aim is to remove friction from getting started, and application behaviour should be easy to understand at a glance.

Much stronger test and tooling coverage

One of the most important changes in v5 is not a runtime feature at all. The branch adds broad PHPUnit coverage across the new application, dispatch, init, redirect, service and view layers, alongside updated static analysis and code quality tooling. This release has much better verification around it.

For users of the framework, this should translate to more confidence in future development. Refactors become safer when behaviour is pinned down by tests, and that makes it easier to keep improving the internals without introducing regressions.

Namespace transition work

This release also continues the move from Gt to GT naming across PHP.GT, with a compatibility layer in place to help bridge the transition.

This is part of a wider tidy-up across the PHP.GT ecosystem, and v5 does the necessary groundwork without forcing everything to change all at once.

What v5 is really about

WebEngine v5 is not a release built around adding lots of surface area. It’s a release about sharpening the core of the framework so that the original ideas behind WebEngine can hold up more cleanly as the project grows.

If you like WebEngine because it lets you start with HTML, keep concerns separate, and write application logic without being buried under framework ceremony, v5 is very much a continuation of that direction.

It is the same idea, but with cleaner and more powerful design decisions behind it.

Automatic security scanning via Github's free tooling

Published on by Greg Bowler

All PHP.GT repositories have just had a new Github Action enabled by default, which scans everything from unit tests to Actions workflow files for security vulnerabilities. CodeQL and Dependabot can be enabled via the Secutity tab on any repository - and some minor patches have already been gathered.

CodeQL immediately caught an issue with how Github Actions was set up across the PHP.GT repositories - in between workflow runs, there was a very short period of time where the action’s artifacts could be intercepted by the Github API, the Github token extracted and used to perform a malicious act on the codebase or repository settings. A quick patch bolting down the permissions of the runner was provided automatically after the first test run, and now every time any commit is made, a full repository scan is performed.

Dependabot checks all upstream requirements for security vulnerabilities, and if any issues are detected, will try to automatically patch a fix in a new pull request. Already, a vulnerability has been discovered and patched! The www.php.gt website repository relies on Markdown for its content management (from Github Wikis). The thephpleague/commonmark library is used to convert Markdown to HTML, but a vulnerability was detected where a malicious user could write some code within a Github Wiki markdown file, so that it would get executed on the server when converting to HTML! Sounds scary, but before the code could even be deployed to the server there was a PR raised to fix this.

The reason I’m writing this update is because I’m so impressed with the free security tooling available to open source projects. I urge every open source contributor to check the Security tab on their GitHub repositories and see what options are available. You may be as pleasantly surprised as I was.

Thank you Github, and thank you to the many contributors that make all of this possible!