where() or orWhere()
The where()
method is the most versatile condition builder in decMuc/PDOdb.
It supports all comparison operators, arrays, subqueries, SQL functions, and even custom injection-safe expressions.
where()
inputs are internally checked for suspicious patterns such as
1; SLEEP(1)
, logic breaks, or unsafe casting. This heuristic system prevents many
types of SQL injection — even if untyped input is passed.
⚠️ For maximum safety, you should use type-specific filters like
whereInt()
or
whereBool()
where possible.
Advanced details: Heuristic WHERE check
This protection layer (internally called PDOdb_HEURISTIC_WHERE_CHECK
) is enabled by default.
You can disable it globally or per instance if required.
Basic usage
The where()
method adds a simple AND condition to the query.
It accepts one to three parameters, depending on the type of comparison:
where(column, value)
– compares with=
by defaultwhere(column, operator, value)
– for custom operators like!=
,>
,LIKE
etc.
$db->where('id', 5);
$db->where('status', 'active');
$db->where('price', '>', 10);
$db->where('title', 'LIKE', '%special%');
$db->get('products');
All where()
conditions are automatically combined using AND.
Adding OR conditions
To add a logical OR between conditions, use the orWhere()
method.
It accepts the same parameters as where()
and must follow an existing condition.
$db->where('status', 'active');
$db->orWhere('status', 'pending');
$db->where('type', 'user');
$db->get('accounts');
This creates a query like:
SELECT * FROM accounts WHERE status = 'active' OR status = 'pending' AND type = 'user'
Mixing where()
and orWhere()
You can chain where()
and orWhere()
freely to build complex conditions
during query composition. This gives you full flexibility for dynamic logic.
$db->where('type', 'user');
$db->orWhere('type', 'admin');
$db->where('active', 1);
$db->orWhere('email_verified', 1);
$db->get('users');
This builds a query like:
WHERE type = 'user' OR type = 'admin' AND active = 1 OR email_verified = 1
Note: Parentheses are not applied automatically.
What values are expected in where()
conditions?
The where()
and orWhere()
methods support a wide range of input types.
However, not all combinations are valid. Here's what is supported:
- Scalar values (
int
,string
,float
) null
(converted toIS NULL
/IS NOT NULL
)- Arrays (for
IN
/NOT IN
) - Subqueries (objects with a
getSubQuery()
method) - Special functions like
$db->now()
The $operator
must be a valid SQL operator (e.g. =
, >
, LIKE
, IN
, IS NOT
).
Anything else will be rejected automatically for safety reasons.
❌ Invalid Examples:
where('id', '1 OR 1=1')
– flagged as suspicious
→ deferred and only blocked if id
is a numeric or strict field
where('col', '(SELECT ... )')
– raw subqueries as strings → not allowed
where('SUM(price)', 100)
– aggregate functions → blocked
This validation is handled automatically by secureWhere()
and can be extended via
whereInt()
, whereDate()
, and similar safe variants.
Chaining multiple where()
and orWhere()
calls
You can call where()
and orWhere()
repeatedly in any order.
All conditions are accumulated until the query is executed.
$db
->where('role', 'customer')
->where('country', 'DE')
->orWhere('newsletter_optin', 1);
$users = $db->get('users');
This generates:
WHERE role = 'customer' AND country = 'DE' OR newsletter_optin = 1
Checking for NULL
and NOT NULL
You can check for NULL
or NOT NULL
values using the standard where()
method by passing null
as the value.
where('column', null)
→ generatesIS NULL
where('column', null, 'IS NOT')
→ generatesIS NOT NULL
// Find all users where deleted_at IS NULL
$db->where('deleted_at', null);
// Find all orders where shipped_at IS NOT NULL
$db->where('shipped_at', null, 'IS NOT');
$db->get('orders');
All where()
conditions are also available as orWhere()
by simply changing the method name.
For improved type safety and readability, you can also use:
whereIS('column')
– forIS NULL
whereIsNot('column')
– forIS NOT NULL
- ...and their
orWhereIS()
/orWhereIsNot()
counterparts
Using BETWEEN
and NOT BETWEEN
conditions
To filter a value range (e.g. prices or dates), pass an array with exactly two values and set the operator to
BETWEEN
or NOT BETWEEN
.
where('price', [10, 20], 'BETWEEN')
→price BETWEEN 10 AND 20
where('created_at', ['2020-01-01', '2020-12-31'], 'NOT BETWEEN')
→ excludes that range
// Match range of prices
$db->where('price', [10, 20], 'BETWEEN');
// Exclude a date range
$db->where('created_at', ['2020-01-01', '2020-12-31'], 'NOT BETWEEN');
$db->get('products');
Use whereBetween()
or
whereNotBetween()
for type-safe variants.
These explicitly validate range values.
orWhere*()
versions are also available.
Using LIKE
and NOT LIKE
To match patterns in a column, use the SQL operators LIKE
or NOT LIKE
together with
percent signs (%
) as wildcards.
The pattern is passed as a string, and you specify the operator explicitly.
where('name', 'John%', 'LIKE')
→ starts with "John"where('email', '%@gmail.%', 'NOT LIKE')
→ exclude Gmail addressesorWhere('notes', '%urgent%', 'LIKE')
→ contains the word "urgent"
// Starts with 'admin'
$db->where('username', 'admin%', 'LIKE');
// Excludes Gmail addresses
$db->where('email', '%@gmail.%', 'NOT LIKE');
// Contains 'SQL injection'
$db->orWhere('notes', '%SQL injection%', 'LIKE');
$db->get('users');
LIKE
and NOT LIKE
are both fully supported.
Just pass the pattern and use the operator explicitly.
LIKE
and NOT LIKE
are both fully supported.
Just pass the pattern and use the operator explicitly.
EXISTS and NOT EXISTS
EXISTS
and NOT EXISTS
are fully supported and allow you to check whether a given subquery
returns any rows. To use these conditions, you must pass a subquery object created via
subQuery()
.
$sub = $db->subQuery('s');
$sub->where('user_id', $db->func('u.id'));
$sub->get('orders', 'user_id');
$db->where('EXISTS', $sub);
// or
$db->where('NOT EXISTS', $sub);
These advanced WHERE conditions rely on subquery support and cannot be used with plain SQL strings. For details and more examples, see Subqueries and Nested Conditions.