Skip to content

Repository files navigation

ZenDB: Injection-Proof SQL for PHP/MySQL

A database layer that's easy to use and hard to misuse. Within microseconds of raw mysqli + htmlspecialchars() (measurements).

  • SQL injection is designed out: Quotes and numbers written into a query are rejected before it runs. Values go through placeholders, not because you remembered, but because there's no other way.
  • XSS is prevented by default: Every value from the database HTML-encodes itself on output. You don't call htmlspecialchars(). Neither does the next developer.
  • Fast to learn, fast to use: The methods mirror SQL: select, insert, update, delete. If you know MySQL, you already know ZenDB, and if you don't, you will soon!

Why SQL?

Most database libraries invent their own query language - chained methods, builder patterns - that ends up just as complex as SQL but less powerful. ZenDB takes the opposite approach: don't teach people a complicated thing that replaces SQL. Just use SQL and make it safe.

SELECT, WHERE, JOIN, ORDER BY - that's all you need to query with ZenDB. The library handles the security (placeholders, escaping, validation) so you can write the SQL you already know without worrying about injection.

30-Second Quickstart

composer require itools/zendb
use Itools\ZenDB\DB;

// Connect
DB::connect([
    'hostname'    => 'localhost',
    'username'    => 'dbuser',
    'password'    => 'secret',
    'database'    => 'my_app',
    'tablePrefix' => 'app_',   // optional
]);

// Select rows
$users = DB::select('users', "status = ?", 'active');
foreach ($users as $user) {
    echo "Hello, $user->name!"; // auto HTML-encoded
}

// Get a single row
$user = DB::selectOne('users', "id = ?", 1);

// Insert a row
$newId = DB::insert('users', [
    'name'  => 'Alice',
    'city'  => 'Vancouver',
]);

// Update a row
$newValues = ['city' => 'Toronto'];
$where     = ['id' => $newId]; // arrays work too
DB::update('users', $newValues, $where);

// Delete a row
DB::delete('users', ['id' => $newId]);

// Full SQL when you need it (:: inserts your table prefix)
$rows = DB::query("SELECT name, city FROM ::users WHERE status = :status AND city = :city", [
    ':status' => 'active',
    ':city'   => 'Vancouver',
]);

Documentation

Full guides and references (browse on GitHub):

  • The Basics (read in order)
    • Getting Started - install, connect, and fetch your first rows
    • Querying Data - WHERE conditions, sorting, and pagination with select(), selectOne(), and count()
    • Working with Results - result sets, rows, and values: HTML-safe output by default, raw access when you need it
    • Modifying Data - insert(), update(), and delete(), plus transactions and SQL expressions like NOW()
    • Placeholders - every placeholder type and when to use each
    • Joins and Custom SQL - full SQL with query() and queryOne(), keeping the same safety guarantees
  • Everyday Use
    • Common Patterns - copy-paste recipes: record-or-404, search filters, paginated lists
    • Helpers and Utilities - raw SQL expressions, pagination SQL, LIKE pattern builders, table prefix conversion
  • Advanced Setup
    • Multiple Connections - connecting to more than one database, or one database with different settings
    • Encryption - automatic column encryption with encryptionKey
  • Lookup
    • Security Gotchas - the narrow cases that still let you write an unsafe query, and the safe form for each
    • Performance - measured page benchmarks: within microseconds of raw mysqli + htmlspecialchars()
    • Troubleshooting - exception messages explained, connection problems, behavior gotchas, debugging
    • Method Reference - every method, parameter, and return type in one place
    • AI Reference - the complete API in one dense file, written for AI coding assistants

When you might NOT want ZenDB

  • You need an ORM with models, migrations, or an ActiveRecord pattern
  • You need to support databases other than MySQL/MariaDB (and compatible alternatives)
  • You need async or non-blocking database queries
  • You prefer writing raw SQL without any abstraction

Companion Libraries

Read queries return SmartArrays, and the values inside them are SmartStrings. Both are installed with ZenDB. Documentation for those libraries is in their own GitHub repos:

  • SmartArray - the collections your query results arrive as, with chainable filtering, sorting, and grouping.
  • SmartString - the fields inside those results: strings that HTML-encode themselves on echo, with chainable formatting, date, and number methods.

Questions?

Post a message in our forum.

License

MIT

About

PHP/MySQL database layer where values only enter SQL through placeholders and every result HTML-encodes itself on output. Within microseconds of raw mysqli + htmlspecialchars().

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages