【问题标题】:How to break queries using regex in php如何在 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 中它抱怨不是固定长度)。

如果有人能给我一些关于如何处理这个问题的提示,我将不胜感激。

【问题讨论】:

    标签: php sql regex


    【解决方案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')
      )
      

      【讨论】:

        猜你喜欢
        • 2013-04-27
        • 2011-07-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-02
        • 1970-01-01
        • 1970-01-01
        • 2010-11-06
        相关资源
        最近更新 更多