Skip to content

Releases: monicahq/laradb

1.1.0

Choose a tag to compare

@djaiss djaiss released this 28 Aug 11:59
Immutable release. Only release title and notes can be modified.
1619361

1.1.0

Laravel 13 support.

  • illuminate/database, http, routing, support and view now accept ^13.0
    alongside ^10.0, ^11.0 and ^12.0.
  • orchestra/testbench widened to ^11.0 for the Laravel 13 leg.
  • The package's own PHP floor stays at ^8.1; Composer resolves the pair per
    project, so Laravel 13's PHP 8.3 requirement does not reach projects on
    older framework versions.
  • The integration matrix grows from 9 jobs to 11, excluding Laravel 13 on
    PHP 8.1 and 8.2.

1.0.1

Choose a tag to compare

@djaiss djaiss released this 28 Aug 11:17
Immutable release. Only release title and notes can be modified.
29286f8

A security release. If you are on 1.0.0, upgrade.

composer require --dev monicahq/laradb:^1.0.1

Both issues were found in an audit of the package rather than reported from the field, and neither is known to have been exploited. Both are cases of a protection that looks present and is not, so neither would have been visible from the page.

An empty middleware config published the viewer unauthenticated

Laravel drops a route group's middleware key when it is not set. A published config with 'middleware' => null — a blank line, a commented-out array, a bad merge — therefore registered both routes with no middleware at all, making every row of every table readable by anyone who found the URL. The ['web', 'auth'] default in the service provider did not catch this, because Config::get() returns null for a key that exists holding null, not the default.

null and [] now fall back to ['web', 'auth']. If you genuinely want the viewer reachable without authentication, say so explicitly with ['web'].

Check your own config: if laradb.middleware is blank, null, or an empty array, your viewer has been unprotected wherever it was enabled. In local that is usually a machine only you can reach — but check anything you enabled with LARADB_ENABLED.

Query failures described the database to the visitor

QueryFailedException embedded the raw PDO message, which quotes the failing statement, the schema it ran against and, on PostgreSQL, the value that broke it. It reached the HTML page and the JSON endpoint alike, and it was reachable from the query string — a foreign key filter with a value of the wrong type is enough to provoke one on PostgreSQL.

The message is generic now. Every exception on its way to a visitor passes through a single method that sends the real cause to the application log, so sanitising is not something a future code path can forget to do.

Also in this release

Documentation only: the readme opens with the problem the package solves, and the foreign-key section was folded into the Routes table.

Verification

Both fixes are covered by tests that fail against 1.0.0's code. The suite — Pint, PHPStan level 8 with strict rules, and 129 tests — passes, and the integration matrix ran green on this commit across PHP 8.1–8.4 × Laravel 10/11/12 against real MySQL and PostgreSQL servers.

Full changelog: 1.0.0...1.0.1

1.0.0

Choose a tag to compare

@djaiss djaiss released this 27 Aug 23:09
Immutable release. Only release title and notes can be modified.
345ffad

A read-only database browser you drop into a Laravel application. Install it, open /db, and get your tables on the left and their rows on the right.

Works with MySQL / MariaDB, PostgreSQL and SQLite.

composer require --dev monicahq/laradb

What you get

  • Every table in the schema in the sidebar, with row counts — exact on SQLite, engine estimates on MySQL and PostgreSQL so listing a large schema stays cheap.
  • The grid, dense and monospace: column types, PK and FK badges, absolute row numbers in a gutter that stays put when you scroll sideways, and NULL rendered as something you can tell apart from an empty string.
  • Follow a foreign key through to the row it points at. The value is a link; clicking it lands you on the target table narrowed to that row, with a chip naming the key you came through.
  • The chrome tells you where you are: engine and version, the database being browsed, its size and index count, the settings the engine reports about itself — and, for the page in front of you, the statement that produced it and how long it took.
  • No CDN. The page ships its own CSS and JavaScript. No build step, no Tailwind, no Alpine. The only remote request is a webfont, and the layout is intact without it.
  • A JSON endpoint on /db/tables/{table}?format=json for when you want the rows rather than the page.

Read-only by construction

The interesting part of a database browser is what it refuses to do.

  • Both routes are GET; the package issues nothing but SELECT.
  • Table names are matched against schema introspection before anything is built — a name outside that whitelist is a 404, never a query.
  • Identifiers are quoted per engine, inner quotes doubled, so a table named we"ird cannot break out of one.
  • LIMIT and OFFSET are integers from arithmetic, never interpolated strings.
  • The one value that comes from the URL — the foreign-key filter — is always bound, and its column must be one a foreign key actually targets.
  • There is no query box. The package cannot run arbitrary SQL because it has nowhere to accept it.
  • Connection errors are sanitised: PDO quotes the DSN and the database user, so the page shows a neutral message and the real error goes to your log.
  • SQLite's absolute file path is shortened to the project root, or the bare filename when it lives outside.

Before you install it

It renders the contents of your database in a web page. Install it with composer require --dev, keep it out of production builds, and put an authorisation gate in front of it — the default ['web', 'auth'] middleware only proves the visitor is someone. See Who can reach it.

Requirements

PHP 8.1+ · Laravel 10, 11 or 12 · ext-pdo

Tested on CI against PHP 8.1–8.4 × Laravel 10/11/12, with real MySQL and PostgreSQL servers.