doushou8299 2019-06-22 14:42
浏览 99
已采纳

解析MySQLi查询语句以获取PDO迁移的参数

This question is about parsing in PHP, not how to migrate MySQLi to PDO.

I want to migrate some old code from MySQLi to PDO. The site has over 400 string query statements. I want to revise the code to use prepared statements.

I.e., convert

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

to

$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();

I started out by parsing the $query string to find 'where', then looking for 'and' to separate parameter/value pairs, etc.

Edit: This is basic code to read lines in a file (in this case, a .php file):

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

when finding a line with a query statement, the line will be a literal string something like this:

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

Then, the code to parse may look something like this:

$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...)

This intuitively is not efficient. Is there a better way to parse the $query string to find the parameters than this? Note that there may be 'order by', etc. in the string that should just append after finding the parameters.

  • 写回答

1条回答 默认 最新

  • douba3975 2019-06-28 17:38
    关注

    I ended up solving this parsing problem using regex. I am sure that there are much more efficient regex patterns that can be used for matching but this served its purpose.

    Reading a line in a PHP file using fgets() yields a string (including the variable name and all syntax), for example:

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

    The first step is to confirm that the line of code includes a SELECT statement with a WHERE clause and is not a commented statement. The WHERE clause is taken out and split by and/or to get conditional pairs of parameter/value.

    Then the parameter/value pairs can be split to allow rewriting the statement according to 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);
    

    The conditional pairs are split by finding comparison operators in each pair.

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

    The values can then be replaced by question marks and the query statement rewritten. The values can also be placed in an array for 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);
    

    I was able to use regex to capture nearly any variation of SELECT statements that I have and quickly update (migrate) my files from MySQLi to PDO. Of course, I have a wrapper function that takes either a simple string for the query statement (MySQLi) or a 2 part array with the query and values (PDO).

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 蓝牙耳机怎么查看日志
  • ¥15 Fluent齿轮搅油
  • ¥15 八爪鱼爬数据为什么自己停了
  • ¥15 交替优化波束形成和ris反射角使保密速率最大化
  • ¥15 树莓派与pix飞控通信
  • ¥15 自动转发微信群信息到另外一个微信群
  • ¥15 outlook无法配置成功
  • ¥30 这是哪个作者做的宝宝起名网站
  • ¥60 版本过低apk如何修改可以兼容新的安卓系统
  • ¥25 由IPR导致的DRIVER_POWER_STATE_FAILURE蓝屏