itools / zendb
Injection-proof PHP/MySQL database layer with automatic XSS-safe output
Requires
- php: ^8.1
- ext-mysqli: *
- ext-openssl: *
- itools/smartarray: ^2.6.6
- itools/smartstring: ^2.6.2
Requires (Dev)
- phpunit/phpunit: ^10.5
This package is auto-updated.
Last update: 2026-08-17 04:51:01 UTC
README
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 impossible: ZenDB rejects any query with inline values. Every dynamic value goes 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 (parameterization,
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(), andcount() - Working with Results - result sets, rows, and values: HTML-safe output by default, raw access when you need it
- Modifying Data -
insert(),update(), anddelete(), plus transactions and SQL expressions likeNOW() - Placeholders - every placeholder type and when to use each
- Joins and Custom SQL - full SQL with
query()andqueryOne(), 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
Related Libraries
- 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