如何在 php 中使用正则表达式中断查询
Posted
技术标签:
【中文标题】如何在 php 中使用正则表达式中断查询【英文标题】:How to break queries using regex in php 【发布时间】:2011-04-29 10:39:33 【问题描述】:假设我有以下字符串:
insert into table values ('text1;'); insert into table values ('text2')
如何使用正则表达式打破这些查询(获取每个单独的查询)?
我发现了一个非常相似的问题:Use regex to find specific string not in html tag ...但它使用特定于 .NET 的解决方案:在查找后面(在 php 中它抱怨不是固定长度)。
如果有人能给我一些关于如何处理这个问题的提示,我将不胜感激。
【问题讨论】:
【参考方案1】:诀窍是计算您传递了多少非转义引号字符。假设 SQL 在语法上是正确的,则在偶数个非转义引号字符之后的分号将是您想要的,而在奇数个非转义引号字符之后的分号将是字符串文字的一部分。 (请记住,字符串文字可以包含正确转义的引号字符。)
如果您想要 100% 的可靠性,您将需要一个真正的 SQL 解析器,例如 this。 (我刚刚在 Google 上搜索了“PHP 中的 SQL 解析器”。我不知道它是否有效。)
编辑:
我认为仅使用正则表达式就不可能找到成对的非转义引号字符。也许正则表达式大师会证明我错了,但在这么多可能的组合中区分转义和未转义的引号字符似乎太难了。我尝试了后向断言和反向引用,但没有成功。
以下不是纯正则表达式解决方案,但我认为它有效:
preg_match_all("/(?:([^']*')2)*[^']*;/U", str_replace("\\'", "\0\1\2", $input), $matches);
$output = array_map(function($str) return str_replace("\0\1\2", "\\'", $str); , $matches[0]);
基本上,我们将转义的引号字符暂时替换为极不可能出现的字节串,在本例中为\0\1\2
。之后,剩下的所有引号字符都是未转义的。正则表达式挑选出前面有偶数个引号字符的分号。然后我们恢复转义的引号字符。 (我在那里使用了一个闭包,所以它只适用于 PHP 5.3。)
如果您不需要处理字符串文字中的引号字符,是的,您可以使用纯正则表达式轻松完成。
【讨论】:
对,但问题的关键是如何使用正则表达式来做到这一点(当然,如果可能的话)。还是谢谢。【参考方案2】:假设 SQL 语法正确,最好用分号分割。
以下正则表达式将起作用,但前提是所有引号都成对出现。
/.+?\'.+?\'.*?;|.+?;/
为了避免转义单引号:
/.+?[^\\\\]\'.+?[^\\\\]\'.*?;|.+?;/
处理多对单引号。
/.+?(?:[^\\]\'.+?[^\\]\')+.*?;|.+?;/
针对以下数据集进行测试:
插入表格值('text1;\'','2');插入表值('text2');插入 test3 值 ('cookie\'','fly');
返回:
插入表格值 ('text1;\' ','2');
插入表格值('text2');
插入test3值('cookie\'','fly');
我不得不承认这是一个非常肮脏的正则表达式。它根本不会处理任何类型的 SQL 语法错误。不过,我很享受提出纯正则表达式的挑战。
【讨论】:
【参考方案3】:你想怎么破?
你可以使用explode('', $query)转换成一个数组。
或者,如果您想使用正则表达式获取 text1 和 text2 值,您可以使用 preg_match( '/(\'([\w]+)\')/', $query, $matches ) where $matches[1]是你的价值。
preg_match_all( '/([\w ]+([\w \';]+))/', $queries, $matches ) 将为您提供此查询模式的所有匹配项。
【讨论】:
我需要休息一下;但是有问题;内引号。可以编写一个小代码来做到这一点,但我想知道是否可以使用正则表达式。 preg_match_all 解决方案可以帮助您。【参考方案4】:正则表达式并不总是擅长这种类型的事情。以下功能应该可以工作:
function splitQuery($query)
$open = false;
$buffer = null;
$parts = array();
for($i = 0, $l = strlen($query); $i < $l; $i++)
if ($query[$i] == ';' && !$open)
$parts[] = trim($buffer);
$buffer = null;
continue;
if ($query[$i] == "'")
$open = ($open) ? false: true;
$buffer .= $query[$i];
if ($buffer) $parts[] = trim($buffer);
return $parts;
用法:
$str = "insert into table values ('text1;'); insert into table values ('text2')";
$str = splitQuery($str);
print_r($str);
输出:
Array
(
[0] => insert into table values ('text1;')
[1] => insert into table values ('text2')
)
【讨论】:
以上是关于如何在 php 中使用正则表达式中断查询的主要内容,如果未能解决你的问题,请参考以下文章