A database driver/plugin that adds Apache Parquet support to Adminer 5.x, built against Adminer's extension/driver API.
Parquet is a columnar on-disk file format, not a database server. This driver
lets you browse and read Parquet files through the normal Adminer UI: list
files as tables, inspect their schema, and run SELECT with search, sort, and
paging. It is read-only — Parquet files are treated as immutable analytical
data.
It is backed by the pure-PHP reader flow-php/parquet,
so there is no native library, FFI, or PDO driver to install — just PHP with
ext-bcmath and ext-zlib.
Adminer's driver API expects three classes in the Adminer namespace plus a set
of free functions (see docs/reference-driver.inc.php and
docs/reference-sqlite.inc.php, kept locally for reference):
| Class / API | Role |
|---|---|
Db |
"connection" wrapper implementing SqlDb; validates and remembers the target path |
Result |
result-set wrapper (fetch_assoc, fetch_row, fetch_field, seek, num_rows) over materialized rows |
Driver |
extends SqlDriver; overrides select() to read rows and apply WHERE/ORDER/LIMIT in PHP; declares types via support() |
| free functions | schema introspection: tables_list, fields, table_status, create_sql, … |
Because there is no SQL engine behind Parquet, Driver::select() does not build a
SQL string. It reads rows directly from the file via flow-php/parquet
(Reader::php()->read($file)->values($columns, $limit, $offset)) and applies
Adminer's WHERE / ORDER BY / LIMIT / paging in PHP. Total row counts come
straight from the Parquet footer metadata (->metadata()->rowsNumber()), so they
are cheap even for large files.
A Parquet file is a single flat table. Adminer's world is server → database → schema → table, mapped as:
| Adminer concept | Parquet |
|---|---|
| Server field | a filesystem path: a directory of *.parquet files (searched recursively), or a single .parquet file |
| database | one implicit database named parquet |
| schema | none |
| table | one per *.parquet file; a file in a subfolder is named by its path relative to the root, e.g. warehouse/sales/2024.parquet → table sales/2024 |
.parq and .pqt are accepted as alternate extensions.
-
PHP 8.3+ with
ext-bcmathandext-zlib -
The
zstdPHP extension (PECL) — many Parquet files are Zstandard-compressed, andflow-php/parquetneedsext-zstdto read those column chunks. Building it requires the PHP development toolchain (phpize) and PECL:# Debian/Ubuntu — install the build toolchain first: sudo apt-get install php-dev php-pear # provides phpize + pecl # then build & install the extension: sudo pecl install zstd
Then enable it. The simplest way is to add the line directly to your
php.ini(runphp --inito find the file(s) in use — note the CLI and web-server SAPIs often use different ini files, so add it to both):; php.ini extension=zstd.so
On Debian/Ubuntu you can instead use the per-extension ini +
phpenmod, which enables it for every SAPI at once:echo "extension=zstd.so" | sudo tee /etc/php/$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')/mods-available/zstd.ini sudo phpenmod zstd
Restart your PHP/web server afterwards, then verify with
php -m | grep zstd(and check the web SAPI too, e.g. via aphpinfo()page). Snappy- and gzip-compressed Parquet work without it, but zstd is the common default from Spark/Arrow/DuckDB exports. -
composer require flow-php/parquet -
Adminer 5.x
This is a drop-in driver. Adminer globs adminer-plugins/*.php at startup and
includes each file, so you only need to place the files there — the top-level
add_driver("parquet", "Parquet") call registers the driver and Parquet
appears in the System dropdown. No adminer_object() bootstrap required.
Lay it out next to your adminer.php:
your-adminer-dir/
├── adminer.php
├── adminer-plugins/ # folder name must be exactly this
│ ├── parquet-driver.php # the driver
│ └── parquet-login.php # login-form relabeling (optional but recommended)
└── vendor/ # from: composer require flow-php/parquet
Steps:
# in your-adminer-dir/
composer require flow-php/parquet
mkdir -p adminer-plugins
cp /path/to/parquet-driver.php /path/to/parquet-login.php adminer-plugins/The single-file adminer.php has no Composer autoloader of its own, so
parquet-driver.php pulls in vendor/autoload.php itself — it looks both next to
the plugin (adminer-plugins/vendor/) and next to adminer.php (../vendor/),
so either location for composer require works.
Verify the reader independently of Adminer:
php -r 'require "vendor/autoload.php";
$f = \Flow\Parquet\Reader::php()->read("data.parquet");
echo $f->metadata()->rowsNumber()." rows\n";
foreach ($f->values([], 5) as $r) echo json_encode($r)."\n";'On Adminer's login screen:
- System: Parquet
- Parquet path: a directory of
.parquetfiles (e.g./var/data/warehouse/) or a single file (e.g./var/data/events.parquet) - Username / Password: ignored
Files under the directory are listed recursively as tables; open one to browse it, search/sort columns, and page through rows.
This driver is read-only by design — Parquet is an immutable columnar file
format read here through the pure-PHP flow-php/parquet library, which has no
write path in this integration. Unlike the DuckDB driver (whose read-only open is
an optional, reversible safety setting), there is no toggle to make Parquet
writable: every mutating hook in parquet-driver.php
(insert/update/delete, create/alter/drop, indexes, foreign keys,
triggers, transactions) returns false, and support() advertises only
columns, table, and dump.
Consequence: browsing and SELECT (search, sort, paging, export) work; anything
that would change data is unavailable.
Adminer still renders its per-row edit links (and the insert/edit forms) for Parquet tables, but because the driver exposes no writable backend those pages end in an error when opened or submitted. This is expected, not a bug: Parquet has no primary key or rowid to address a single row by, and there is nothing to save changes to. Use select (the table browse view) to inspect data; ignore the edit links.
If you need to modify the data, do it at the source that produces the Parquet files (Spark, Arrow, DuckDB, pandas, …) and re-export; Adminer is a viewer here.
Browsing the file/table list (recursive), viewing a table's columns and types,
row counts and file sizes, SELECT with search (=, <, >, <=, >=, !=,
LIKE, IN, IS NULL, …), multi-column sort, paging, a reference
CREATE TABLE reconstruction, and export (dump).
Nested LIST / MAP / STRUCT columns are shown JSON-encoded (marked "nested"
in the field list).
Note: this driver is read-only — there is no writable mode for Parquet. See Read-only mode, including why the Edit links lead to an error.
Everything that mutates or requires a SQL engine — the free-text SQL command
page, INSERT/UPDATE/DELETE, CREATE/ALTER/DROP, indexes, foreign keys,
triggers, stored routines, transactions, and EXPLAIN. Parquet is read-only here
by design; joins and aggregations across files are not available (no SQL engine).
parquet-driver.php the driver (self-contained, namespace Adminer) — goes in adminer-plugins/
parquet-login.php login-form relabeling helper — goes in adminer-plugins/
composer.json dependencies (flow-php/parquet, ext-bcmath, ext-zlib)
docs/ local copies of the Adminer API files used as reference