P粉6198961452023-09-03 10:06:17
First, consider using named parameters instead of <代码>? 代码>. In this case you don't need to replace anything: the named parameters are clear and fairly easy to show in the logs, and are supported by most dbms clients for debugging purposes.
If named parameters are not feasible (due to the size of your current codebase or any other reason), you have two main approaches:
If you choose the latter approach, here is an example of how to do it quickly and dirty:
Replace in multiple steps:
?
with something else that is highly unlikely to appear in the parameter or query. For example\?
. ?
, but will not match the substitution in the first step. If replaced with \?
, it is (?
\?
in the result with ?
. NOTE: The results of this substitution should never be used as a query in a program. This replacement has the potential to implement any or all of the following:
?
instead as a parameter (e.g. in a comment), the results are inaccurate, \?
in our example), the results will be inaccurate. <?php $query = 'UPDATE `list` set `item`=?,`type`=? WHERE (`id` = ?);'; $params = array( 'item' => '1', 'type' => 'Are you o\'k?', 'id' => 2 ); function substitute_params($query, $params) { $prep_params = str_replace(array("'","?"),array("''","\?"),$params); $query = array_reduce($prep_params, function ($interm, $param) { return preg_replace('/(?<!\\)\?/m', is_numeric($param) ? $param : '\'' . $param . '\'', $interm, 1); }, $query); return "-- Not to be used as a query to database. For demonstration purposes only!\n" .str_replace("\?", "?", $query); } echo substitute_params($query, $params); ?>
Output:
-- Not to be used as a query to database. For demonstration purposes only! UPDATE `list` set `item`=1,`type`='Are you o''k?' WHERE (`id` = 2);
Edit: To try to reduce the impact of question marks within constant strings and quoted names, you can try using this replacement:
return preg_replace('/^([^"\'`]*?(?:(?:`[^`]*?`[^"\'`]*?)*?(?:"[^"]*?"[^"\'`]*?)*?(?:\'[^\']*?\'[^\'"`]*?)*?)*?)(?<!\\)\?/m', ''.(is_numeric($param) ? $param : '\'' . $param . '\''), $interm, 1);
It only replaces ?
outside the block quoted with "`'
.
You can view the demo here.
Please keep in mind that this is not a fully fledged parser. For example, it doesn't know about comments. So the possibility of incorrect substitution remains high.