v0.6.2

<p>URLs are limited to lowercase slugs and file names, error messages and URL fields are locked down, and registry queries escape LIKE wildcards.</p>

5 October 2026

Added

  • A URL grammar. A page path segment is V::slug() (lowercase letters and digits with single hyphens) and a file name is V::filename() (photo.jpg, htmx.min.js). Request::$valid is false for any path outside it, and App answers 404 without looking anything up. The same holds for a block that isn't a slug and a revision that isn't hex. The {slug} route token and Page::move() use the grammar, and a collection item uuid must be a slug.
  • Str::slug() is ASCII only. It transliterates Latin letters with a fixed table instead of iconv, whose output depends on the libc, and drops the rest. A name with nothing Latin left slugs to an empty string and is rejected. San::filename() slugs the stem and lowercases the extension.
  • phlat files:fix renames existing files that fall outside the grammar and reports the ones it can't.
  • Log::error() writes to the PHP error log, and Db::like() escapes %, _ and \ for LIKE ... ESCAPE '\'.
  • registry:check reports pages whose index.json lacks created or updated, and --heal stamps them through Page::save().

Changed

  • A visitor sees an exception's message only when it is an HttpException or debug is on. Anything else shows "Something went wrong" and goes to the log, as does every 5xx.
  • San::url() and V::url() accept only http, https and mailto URLs. javascript:, vbscript: and file: URLs fail.
  • Revision URLs (~rev) are for editors only; anyone else gets a 403.
  • A session whose user has been deleted counts as signed out.
  • A HEAD request is answered by the GET route.
  • Arr::mergeRecursive() replaces a list instead of merging it by index, as in JSON Merge Patch. A config layer can now shrink a list as well as grow it.
  • {all} routes always pass one capture, empty when nothing follows.
  • Image variant filenames use a preset name only when it is a valid slug, otherwise a hash. A variant is encoded in the format its extension names. PageFile::url() and PageImage::url() add the source's modification time as a cache-busting token.
  • Deleting a page also removes its collection items, public mirrors and variant rows (Registry::deleteSubtree() is public).
  • The code fieldtype builds its highlighter on first use. Record memoizes its field values.
  • compose.yaml no longer runs the FrankenPHP app service. The shipped admin icon is phlatpage-icon-2x.png.

Fixed

  • Registry *=, ^= and $= matched % and _ in the search value as wildcards.
  • A loose match on a list field returned the same page once per matching entry, and countRows() counted it that often.
  • A list entry or a URL path segment of 0 was dropped as empty.

Comments

No comments yet. Be the first!

Loading form…