替换:IN语句中的参数,其周围的函数重复

时间:2015-03-20 09:56:18

标签: php regex

我想通过将表达式乘以:firstname数组中的元素来替换查询的参数$firstnames

这是我到目前为止所得到的:

$query = "SELECT * FROM test WHERE col1 IN(UNHEX(:firstname)) OR IN (UNHEX('foo'))";

$firstnames = array("Jack", "John", "Michael");
$replacement = "";
foreach ($firstnames as $key => $value) {
    $replacement .= "\${1}".$key.",";
}
$replacement = rtrim($replacement,",");

$pattern = "/(:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)/i";
$query = (preg_replace($pattern, $replacement, $query)).",";

echo $query;

到目前为止,我只更换了参数,但没有替换它周围的函数。可能还有其他几个函数或字符串连接也应该是重复替换的一部分。也可能有一些嵌套的括号。因此,这将是获取IN语句的所有嵌套括号的模式:

$pattern= "/(\s*IN\s*)(\(((?>[^()]+)|(?2))*\))/i";

我无法找到一种方法来组合这两个语句,以正确地替换参数和包裹它的东西。另外,如果IN语句中没有参数,则不应替换。这应该是结果:

$query = "SELECT * FROM test WHERE col1 IN(UNHEX(:firstname1), UNHEX(:firstname2), UNHEX(:firstname3)) OR IN (UNHEX('foo'))";

更新:解决方案! 与此同时,我偶然发现了几个问题,但最终解决了这个问题。

似乎不可能通过使用正则表达式来获取所有内容。因此我决定使用preg_replace_callback功能。在第一步中,我得到了整个IN函数,由它的所有嵌套括号决定。在第二步中,我得到参数,用所需的重复次数替换它。 以下解决方案:

$params = array(
    "firstname" => array("Jack", "John", "Michael")
);

$query = "SELECT * FROM test WHERE col1 IN  (UNHEX(:firstname)) OR col2 IN(UNHEX('foo'))";

function createIN($query, $arrParam) {
    return preg_replace_callback(
        "/(\\s*IN\s*(\\((?:(?>[^()]+)|(?2))*\)))/is", 
        function ($matches) use($arrParam) {
            $pattern = "/(\s*IN\s*\()((.*?((['\"`]).*?\5)?)*)(:[a-zA-Z_][a-zA-Z0-9_]*)(.*)(\))/is";
            preg_match($pattern, $matches[1], $matches2);
            $replacement = $matches[0];
            if(isset($matches2[6])) {
                $replacement = $matches2[1];
                foreach ($arrParam[substr($matches2[6],1)] as $key => $value) {
                    $replacement .= $matches2[2].$matches2[6].$key.$matches2[7].",";
                }
                $replacement = rtrim($replacement,",").$matches2[8];
            }
            return $replacement;
        }, 
        $query
    );
}

echo createIN ($query, $params);

2 个答案:

答案 0 :(得分:1)

动态创建查询,并使用预准备语句。一种简单的方法是将每个参数名称添加到数组中,然后使用implode()将数组转换为逗号分隔的名称列表。这个例子应该有效:

$query = "SELECT * FROM test WHERE col1 IN(";

$firstnames = array("Jack", "John", "Michael");
$params = array();
$query_in = array();
foreach ($firstnames as $key => $value) {
    //$params[] = $value;
    //$query_in[] = "?";
    // Use this for named parameters:
    $params[":param".$key] = $value;
    $query_in[] = ":param".$key;
}

$query .= implode(",",$query_in);
$query .= ") OR IN (UNHEX('foo'))";
/** @var PDO $pdo */
$stm = $pdo->prepare($query);
$stm->execute($params);

echo $stm->queryString;

答案 1 :(得分:1)

如果您真的在寻找正则表达式解决方案:

更改评论:

最后:

$query = "SELECT * FROM test WHERE col1 IN(UNHEX(CONCAT(UPPER(CONCAT(:firstname, 'baz')), 'bar', 'quz'))) OR col1 IN (UNHEX('foo'))";

$firstnames = array("Jack", "John", "Michael");

$pattern = '/((\w+\()+:firstname)(\D+)*((\))+)/i';
if (preg_match($pattern, $query, $matches) === 1) {
    $match = substr(preg_replace('/(IN\s*\()/i', '', $matches[0]), 0 ,-1);
    $function = substr($match, 0, strpos($match, ':firstname'));
    $brackets = substr($match, strpos($match, ':firstname')+10);
    foreach ($firstnames as $key => $value) {
        isset($replacement) ? $replacement .= ",{$function}:firstname{$key}{$brackets}" : $replacement = "{$function}:firstname{$key}{$brackets}";
    }
}

$query = str_replace($match, $replacement, $query);

echo $query;

$query = SELECT * FROM test WHERE col1 IN(UNHEX(CONCAT(UPPER(CONCAT(:firstname0, 'baz')), 'bar', 'quz')),UNHEX(CONCAT(UPPER(CONCAT(:firstname1, 'baz')), 'bar', 'quz')),UNHEX(CONCAT(UPPER(CONCAT(:firstname2, 'baz')), 'bar', 'quz'))) OR col1 IN (UNHEX('foo'))

希望有所帮助。


真的终于:

$query = "SELECT * FROM test WHERE col1 IN(UNHEX(CONCAT('paz', UPPER(CONCAT('qaz', 'qar', :firstname, 'baz')), 'bar', 'quz'))) OR col1 IN(UNHEX(CONCAT('paz', UPPER(CONCAT('qaz', 'qar', :lastname, 'baz')), 'bar', 'quz'))) OR col1 IN (UNHEX('foo'))";

$firstnames = array("Jack", "John", "Michael");
$parameters = array(':firstname', ':street', ':lastname');
$pattern = '/((\w+\()+)(\D+)(:[a-z])(\D+)*((\))+)/i';

if (preg_match_all($pattern, $query, $matches) >= 1) {
    $tempMatches = array();
    if (is_array($matches[0])) {
        foreach ($matches[0] as $moreMatches) {
            $tempMatches[] = $moreMatches;
        }
    } else {
        $tempMatches[] = $matches[0];
    }
    foreach ($tempMatches as $myMatches) {
        $match = substr(preg_replace('/(IN\s*\()/i', '', $myMatches), 0 , -1);
        foreach ($parameters as $param) {
            if (strpos($myMatches, $param)) {
                $function = substr($match, 0, strpos($match, $param));
                $brackets = substr($match, strpos($match, $param) + strlen($param));
                foreach ($firstnames as $key => $value) {
                    isset($replacement) ? $replacement .= ",{$function}{$param}{$key}{$brackets}" : $replacement = "{$function}{$param}{$key}{$brackets}";
                }
                $query = str_replace($match, $replacement, $query);
                unset($replacement);
            }
        }
    }
}

echo $query;

output = SELECT * FROM test WHERE col1 IN(UNHEX(CONCAT('paz', UPPER(CONCAT('qaz', 'qar', :firstname0, 'baz')), 'bar', 'quz')),UNHEX(CONCAT('paz', UPPER(CONCAT('qaz', 'qar', :firstname1, 'baz')), 'bar', 'quz')),UNHEX(CONCAT('paz', UPPER(CONCAT('qaz', 'qar', :firstname2, 'baz')), 'bar', 'quz'))) OR col1 IN(UNHEX(CONCAT('paz', UPPER(CONCAT('qaz', 'qar', :lastname0, 'baz')), 'bar', 'quz')),UNHEX(CONCAT('paz', UPPER(CONCAT('qaz', 'qar', :lastname1, 'baz')), 'bar', 'quz')),UNHEX(CONCAT('paz', UPPER(CONCAT('qaz', 'qar', :lastname2, 'baz')), 'bar', 'quz'))) OR col1 IN (UNHEX('foo'))