1

I prepare my DB request for prevent SQL injection with the extension Mysqlnd. A request like this work on my site :

SELECT a, b FROM table where a = ?;

This next request doesn't work on my site:

SELECT a, b FROM table where b > DATE_SUB(CURRENT_TIMESTAMP(),INTERVAL ? ?);

Error log : PHP Fatal error: Call to a member function execute() on a non-object in ..." This is because the syntax of the request is wrong.

When I try it in my DB IDE, the double question mark count as one and not as 2 parameters.

How can I resolve this problem ?

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Clément M
  • 43
  • 4

2 Answers2

3

With a placeholder, you can bind only data literals, in other words - strings and numbers.

INTERVAL accepts two arguments, expression and unit.

While the expression part is a number and can be bound all right, the unit part is a keyword and therefore cannot be bound. So you can only whitelist it. Here is a white-listing function I wrote that could help with the matter.

$unit = white_list($_GET['unit'], ["DAY","MINUTE","SECOND"], "Invalid time unit name");
$sql = "SELECT a, b FROM table where b > DATE_SUB(CURRENT_TIMESTAMP(),INTERVAL ? $unit)";

it is not very tidy but at least concise and safe.

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
0

Whitout extra functions, and the full INTERVAL list:

$timeFormat = "MINUTE"; //get the $timeFormat value from elsewhere
$timeFormatWhitelist = array("MICROSECOND","SECOND","MINUTE","HOUR","DAY","WEEK","MONTH","QUARTER","YEAR","SECOND_MICROSECOND","MINUTE_MICROSECOND","MINUTE_SECOND","HOUR_MICROSECOND","HOUR_SECOND","HOUR_MINUTE","DAY_MICROSECOND","DAY_SECOND","DAY_MINUTE","DAY_HOUR","YEAR_MONTH");

if (in_array($timeFormat, $timeFormatWhitelist)) {
    $query = "SELECT * FROM table WHERE `dateTime` <= DATE_SUB(CURRENT_TIMESTAMP(),INTERVAL ? $timeFormat)";
    // your prepared statement and do something with the result
}