如何在 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 中使用正则表达式中断查询的主要内容,如果未能解决你的问题,请参考以下文章

在 php 中使用正则表达式进行排列

PHP:正则表达式查询 [关闭]

如何在 PHP 中使用正则表达式匹配空格、回车和换行?

Grafana + Prometheus 如何在查询指标中使用正则表达式?

如何在 django 查询中使用正则表达式

如何在 SQLite 查询中使用正则表达式?