【问题标题】:Parse MySQLi query statement to get parameters for PDO migration解析 MySQLi 查询语句以获取 PDO 迁移的参数
【发布时间】:2019-11-05 01:39:16
【问题描述】:

这个问题是关于 PHP 中的解析,而不是如何将 MySQLi 迁移到 PDO。

我想将一些旧代码从 MySQLi 迁移到 PDO。该站点有 400 多个字符串查询语句。我想修改代码以使用准备好的语句。

即转换

$query = 'SELECT * from table where x='.$x.' and y > '.$y.' or (z<= 35 and auth like "%ed")'
$result = $conn->query($query);

$query = 'SELECT * from table where x = ? and y > ? or (z <= ? and auth like ?)';
$stmt = $conn->prepare($query);
$stmt->bind_param($x, $y, $35, '%ed');
$stmt->execute();

我首先解析 $query 字符串以查找“where”,然后查找“and”以分隔参数/值对等。

编辑:这是读取文件(在本例中为 .php 文件)中的行的基本代码:

$fn = fopen("myfile.php","r+");
while(!feof($fn))  {
    $line = fgets($fn);
    if (strpos($line, 'select'){
       // add parse code here
    };
}

当找到带有查询语句的行时,该行将是一个文字字符串,如下所示:

($line = ) $query = 'select * from menu where authlvl>0 and authlvl

那么,要解析的代码可能是这样的:

$where = substr($line, strpos($line, 'where') + 5);
$pair = array();
$j = 0;
$st = 0;
if (strpos(substr($where, $st), 'and', $st)) > 0){
    while (($and = strpos(substr($where, $st), 'and', $st)) > 0){
        $pair[$j] = trim(substr($where, $st, $and - 1));
        $pair[$j+1] = trim(substr($where, $and + 4));
        $st = $and;
        $j++;
    }
}
$ops = array(' ', '<', '>', '=');
(find operators to identify parameters and values for each pair...)

这在直觉上是没有效率的。有没有比这更好的方法来解析 $query 字符串来查找参数?请注意,字符串中可能有“order by”等,应该在找到参数后才附加。

【问题讨论】:

  • 当然。我正在编写解析代码来查找所有查询语句并进行转换。我编写代码来修改文件没有问题。我正在寻找一种通过查找关键组件(例如运算符)来解析代码的基本方法。
  • 你含糊其辞。在您的最后一段代码中,$query 中究竟存在什么?是PHP源代码吗?它看起来像什么?
  • 听起来是一个具有挑战性的项目。但让我们现实地看待这一点。能够编写一个解析器来正确解析每个语句,而手动编辑它们所需的时间更短。 400 可能听起来很多。 IT 将比人们想象的更快。这样看。如果这是一个系统,你需要从长远来看。您将深入了解系统并训练您的大脑快速解析 SQL。
  • 我添加了更多细节以帮助理解具体问题。
  • susbstr/strpos 完全不足以解决这样的问题。使用一些正则表达式检测和提取,如果有的话。还想出 any 包装函数,而不是在准备/绑定/执行代码块之间涂抹参数绑定。

标签: php parsing mysqli pdo


【解决方案1】:

我最终使用正则表达式解决了这个解析问题。我确信有更有效的正则表达式模式可用于匹配,但这达到了它的目的。

使用 fgets() 读取 PHP 文件中的一行会产生一个字符串(包括变量名和所有语法),例如:

$query = 'select * from menu where authlvl>0 and authlvl<=' . $authlvl . ' order by title';

第一步是确认该代码行包含一个带有 WHERE 子句的 SELECT 语句,而不是注释语句。 WHERE 子句被取出并按和/或拆分以获得参数/值的条件对。

然后可以拆分参数/值对以允许根据 PDO 重写语句。

if (preg_match('/(=\s*\'select|=\s*"select)/', $line) && preg_match('/(where)/i', $qry) && !preg_match('/^(\s*\/\/)/', $line)) {
    $z = preg_match('/(?<=where).+/i', $qry, $matches);
    $where = trim($matches[0]);
    $pairs = preg_split('/( and | or )/', $where);
    $andor = preg_match_all('/(\s*and\s*|\s*or\s*)+/', $where, $ao);

通过在每对中查找比较运算符来拆分条件对。

preg_match('/.+?(?:[\=<>]+)/', $pair, $par)
preg_match('/[^(' . preg_quote($par[0]) . ')].*/', $pair, $val)

然后可以用问号替换这些值并重写查询语句。这些值也可以放置在 PDO 的数组中。

$query = 'select * from menu where authlvl > ? and authlvl <= ? order by title';
$values = array('0', $authlvl);
$stmt = $this->pdosc->prepare($query);
$stmt->execute($values);
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

我能够使用正则表达式来捕获我拥有的几乎所有 SELECT 语句的变体,并快速将我的文件从 MySQLi 更新(迁移)到 PDO。当然,我有一个包装函数,它接受一个简单的查询语句字符串(MySQLi)或一个包含查询和值的两部分数组(PDO)。

【讨论】:

    猜你喜欢
    • 2018-09-15
    • 2016-09-11
    • 2012-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-15
    • 2018-06-20
    • 2010-10-20
    相关资源
    最近更新 更多