SqlWhereValidator
in package
SQL WHERE clause validator to prevent SQL injection attacks
SECURITY NOTE: This class does NOT provide a sanitize() method by design. Attempting to sanitize SQL input is dangerous and error-prone. Instead:
- Use isValid() to REJECT dangerous input (defense in depth)
- Use PDO prepared statements with parameter binding (primary defense)
- Never concatenate user input into SQL queries
Why no sanitize() method:
- addslashes() is unsafe (doesn't handle multi-byte encodings like GBK)
- String escaping cannot protect against all SQL injection vectors
- Future maintainers might assume sanitize() makes input safe (it doesn't)
- The correct solution is parameterized queries, not string manipulation
Table of Contents
Constants
- DANGEROUS_PATTERNS = [ // SQL comments '/--/', '~\/\*[^*]*\*+(?:[^/*][^*]*\*+)*\/~', // ReDoS-safe: matches balanced block comments '/#/', // SQL commands '/\b(DROP|CREATE|ALTER|TRUNCATE|DELETE|INSERT|UPDATE|REPLACE|GRANT|REVOKE)\b/i', // Stacked queries '/;\s*\w+/', // Union attacks '/\bUNION\b/i', // Subqueries (can be dangerous in WHERE clauses) '/\bSELECT\b.{0,200}?\bFROM\b/i', // ReDoS-safe: non-greedy with max length // System functions that could be exploited '/\b(SLEEP|BENCHMARK|LOAD_FILE|OUTFILE|DUMPFILE)\b/i', // Information schema access '/\b(INFORMATION_SCHEMA|MYSQL|PERFORMANCE_SCHEMA)\b/i', // Hexadecimal literals (often used in attacks) '/0x[0-9a-fA-F]+/', // CHAR function (used to obfuscate attacks) '/\bCHAR\s*\(/i', ]
- Dangerous SQL patterns that could indicate SQL injection
- MAX_WHERE_LENGTH = 10000
- Maximum allowed WHERE clause length to prevent ReDoS attacks Reasonable limit: most legitimate WHERE clauses are much shorter
Methods
- isValid() : bool
- Validate a WHERE clause for SQL injection attempts
- parseSimpleWhere() : array<string|int, mixed>|false
- Parse a simple WHERE clause into safe components Only allows basic conditions like: column = 'value', column > 123, etc.
- countUnescapedQuotes() : int
- Count unescaped quotes in a string, properly handling escaped backslashes
- stripStringLiterals() : string
- Strip string literals from a WHERE clause, preserving structure
Constants
DANGEROUS_PATTERNS
Dangerous SQL patterns that could indicate SQL injection
private
mixed
DANGEROUS_PATTERNS
= [
// SQL comments
'/--/',
'~\/\*[^*]*\*+(?:[^/*][^*]*\*+)*\/~',
// ReDoS-safe: matches balanced block comments
'/#/',
// SQL commands
'/\b(DROP|CREATE|ALTER|TRUNCATE|DELETE|INSERT|UPDATE|REPLACE|GRANT|REVOKE)\b/i',
// Stacked queries
'/;\s*\w+/',
// Union attacks
'/\bUNION\b/i',
// Subqueries (can be dangerous in WHERE clauses)
'/\bSELECT\b.{0,200}?\bFROM\b/i',
// ReDoS-safe: non-greedy with max length
// System functions that could be exploited
'/\b(SLEEP|BENCHMARK|LOAD_FILE|OUTFILE|DUMPFILE)\b/i',
// Information schema access
'/\b(INFORMATION_SCHEMA|MYSQL|PERFORMANCE_SCHEMA)\b/i',
// Hexadecimal literals (often used in attacks)
'/0x[0-9a-fA-F]+/',
// CHAR function (used to obfuscate attacks)
'/\bCHAR\s*\(/i',
]
MAX_WHERE_LENGTH
Maximum allowed WHERE clause length to prevent ReDoS attacks Reasonable limit: most legitimate WHERE clauses are much shorter
private
mixed
MAX_WHERE_LENGTH
= 10000
Methods
isValid()
Validate a WHERE clause for SQL injection attempts
public
static isValid(string $whereClause) : bool
Parameters
- $whereClause : string
-
The WHERE clause to validate
Return values
bool —True if safe, false if potentially dangerous
parseSimpleWhere()
Parse a simple WHERE clause into safe components Only allows basic conditions like: column = 'value', column > 123, etc.
public
static parseSimpleWhere(string $whereClause) : array<string|int, mixed>|false
Parameters
- $whereClause : string
Return values
array<string|int, mixed>|false —Array of parsed conditions or false if unsafe
countUnescapedQuotes()
Count unescaped quotes in a string, properly handling escaped backslashes
private
static countUnescapedQuotes(string $str, string $quoteChar) : int
Correctly handles:
- Backslash-escaped quotes: ' or "
- Escaped backslashes before quotes: \' or \"
- SQL-style doubled quotes: '' or ""
Example: 'C:\' has 2 unescaped single quotes (the \ is escaped backslash, not escaped quote)
Parameters
- $str : string
-
String to check
- $quoteChar : string
-
Quote character to count (' or ")
Return values
int —Number of unescaped quotes
stripStringLiterals()
Strip string literals from a WHERE clause, preserving structure
private
static stripStringLiterals(string $str) : string
Removes all content inside single-quoted, double-quoted, and backtick-quoted strings, properly handling escaped quotes and backslashes. This prevents false positives when checking for SQL injection patterns (e.g., "John -- Smith" won't trigger comment detection).
Parameters
- $str : string
-
String to process
Return values
string —String with all literal contents removed