几年前我写了这个小函数:
function sqlvprintf($query, $args)
{
global $DB_LINK;
$ctr = 0;
ensureConnection();
$values = array();
foreach ($args as $value)
{
if (is_string($value))
{
$value = "'" . mysqli_real_escape_string($DB_LINK, $value) . "'";
}
else if (is_null($value))
{
$value = 'NULL';
}
else if (!is_int($value) && !is_float($value))
{
die('Only numeric, string, array and NULL arguments allowed in a query. Argument '.($ctr+1).' is not a basic type, it\'s type is '. gettype($value). '.');
}
$values[] = $value;
$ctr++;
}
$query = preg_replace_callback(
'/{(\\d+)}/',
function($match) use ($values)
{
if (isset($values[$match[1]]))
{
return $values[$match[1]];
}
else
{
return $match[0];
}
},
$query
);
return $query;
}
function runEscapedQuery($preparedQuery )
{
$params = array_slice(func_get_args(), 1);
$results = runQuery(sqlvprintf($preparedQuery, $params));
return $results;
}
这允许在一个单行的类似于C#的String.Format字符串中运行语句,例如:
runEscapedQuery("INSERT INTO Whatever (id, foo, bar) VALUES ({0}, {1}, {2})", $numericVar, $stringVar1, $stringVar2);
它在考虑变量类型时会逃避。如果您尝试将表格、列名参数化,由于它将每个字符串放在引号中,这是无效的语法,因此会失败。
安全更新:之前的str_replace
版本允许通过将{#}令牌添加到用户数据中进行注入。这个preg_replace_callback
版本如果替换内容包含这些令牌不会出现问题。