Doctrine Expr的literal函数是否内部使用预准备语句?两种用法安全性确认
literal() Usages Safe Against SQL/Wildcard Injection? Great question—let’s break down both scenarios to verify their safety, and clarify how literal() works compared to standard parameter binding.
Scenario 1: Numeric Arithmetic Comparison
$expr = $queryBuilder->expr()->orX(); $expr->add($queryBuilder->expr()->lt( 'entityName.field - ' . $queryBuilder->expr()->literal($rule->getValue()), $queryBuilder->expr()->literal(self::MAX_ERROR) ));
This is fully safe against SQL injection. Here’s why:
- Doctrine’s
literal()method escapes values according to your database’s platform rules (e.g., MySQL, PostgreSQL) before embedding them directly into the SQL string. For numeric inputs, this ensures the value is treated as a literal number, blocking any malicious SQL from being injected. - Even though
self::MAX_ERRORis a constant, wrapping it inliteral()is harmless—it adds consistency and ensures the value is formatted correctly for your database. - Wildcard injection isn’t a concern here, since we’re performing a numeric comparison, not a
LIKEquery.
Scenario 2: LIKE Query with Escaped Wildcards
$expr = $queryBuilder->expr()->orX(); $expr->add($queryBuilder->expr()->like( 'entityName.field', $queryBuilder->expr()->literal(addcslashes($rule->getValue(), '%_') . '%') ));
This is also safe against both SQL injection and wildcard injection, let’s break down the two layers of protection:
- SQL Injection Defense:
literal()handles escaping of SQL-specific characters (like single quotes) to prevent attackers from breaking out of the string literal and injecting arbitrary SQL. - Wildcard Injection Defense: You’re using
addcslashes($rule->getValue(), '%_')to escape the wildcard characters%and_before appending the trailing%for theLIKEmatch. This ensures user input like%test%is treated as a literal string (with escaped%s) instead of matching any string containing "test". Theliteral()method preserves this escaping when embedding the value into the SQL.
A Quick Note: literal() vs Parameter Binding
While both usages are safe, keep in mind that parameter binding (via setParameters()) is generally the preferred approach in Doctrine. It leverages database prepared statements, which are more secure in edge cases and can boost performance via query caching. That said, literal() is a valid tool for scenarios where parameter binding isn’t feasible (like your arithmetic expression), and when used correctly, it’s just as effective against injection.
内容的提问来源于stack exchange,提问作者zozo

