PHP регулярное выражение, заменить каждый заполнитель в SQL-запрос

Я пытаюсь вручную связать VAR-запросы в SQL-запросах с помощью PHP регулярных выражений:

$query = 'SELECT * FROM table WHERE a = '.'\''.mysql_real_escape_string(":bar \' :bar ' :bar ' :bar \' :bar").'\''.' OR foo = :foo AND fooo = :foo_o AND bar = :bar';
$binding = array(
':foo_o' => 'good',
':foo' => 'nice',
'bar' => 'owned'
);
echo preg_replace_callback("/:\\w+(?![^']*'(?:(?:[^']*'){2})*[^']*$)/u", function($match) use($binding) {
if(isset($binding[ltrim($match[0], ':')])) {
return $binding[ltrim($match[0], ':')];
} else if(isset($binding[$match[0]])) {
return $binding[$match[0]];
} else {
return $match[0];
}
},  $query);

Результат:

SELECT * FROM table WHERE a = ':bar \\\' owned \' :bar \' owned \\\' :bar' OR foo = nice AND fooo = good AND bar = owned

Как вы можете видеть, два заполнителя внутри кавычек экранированы, но не должны.


Я также попытался использовать регулярное выражение отсюда (https://stackoverflow.com/a/5610067/4965547 ) что я уже использовал для разделения нескольких запросов, и это хорошо сработало для этого, но не для привязки:

echo preg_replace_callback('%:\\w+((?=\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'|"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|/*[^*]*\*+([^*/][^*]*\*+)*/|\#.*|--.*|[^"\'#])+(?:\\w|$))%xu', function($match) use($binding) {
if(isset($binding[ltrim($match[0], ':')])) {
return $binding[ltrim($match[0], ':')];
} else if(isset($binding[$match[0]])) {
return $binding[$match[0]];
} else {
return $match[0];
}
},  $query);

В этом случае каждый заполнитель заменяется даже между кавычками:

SELECT * FROM table WHERE a = 'owned \\\' owned \' owned \' owned \\\' owned' OR foo = nice AND fooo = good AND bar = owned

Любой regex pro, который может помочь мне исправить одно из двух выражений? Заранее спасибо.


PSДа, я знаю, что должен использовать PDO, но я хочу создать не PDO-адаптер для использования в расширении mysql PHP, и да, я также знаю, что это расширение будет удалено. Также я хочу не использовать PHP-скрипт как можно чаще, я действительно хочу сделать это с помощью регулярных выражений.


Изменить 06/05/2015Я наконец понял, как работает сложное регулярное выражение, и нашел решение. Поэтому я публикую это здесь на тот случай, если кому-то это понадобится или будет интересно

Связывание с именованными заполнителями:

$query = 'SELECT * FROM table WHERE a = \''.mysql_real_escape_string(":bar \' :bar ' :bar ' :bar \' :bar").'\' OR b = \''.mysql_real_escape_string(':bar \" :bar " :bar " :bar \" :bar').'\' OR foo = :foo  AND fooo = :foo_o AND bar = :bar';
$binding = array(
':foo_o' => 'good',
':foo' => 'nice',
':bar' => 'owned'
);
echo preg_replace_callback('%(:\w+)\W*|(?:\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'|"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|/*[^*]*\*+([^*/][^*]*\*+)*/|\#.*|--.*|[^"\':#])+%u', function($match) use($binding) {
if(isset($match[1]) && isset($binding[$match[1]])) {
return str_replace($match[1], $binding[$match[1]], $match[0]);
} else {
return $match[0];
}
},  $query);

То же самое с заполнителями вопросительного знака:

$query = 'SELECT * FROM table WHERE a = '.'\''.mysql_real_escape_string("? \' ? ' ? ' ? \' ?").'\''.' OR '.'\''.mysql_real_escape_string('? \" ? " ? " ? \" ?').'\''.' OR foo = ? AND fooo = ? AND bar = ?';
$binding = array(
1 => '*1',
2 => '2*?',
3 => 'lol',
4 => 'none'
);
$count = 0;
echo preg_replace_callback('%\?|(?:\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'|"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|/*[^*]*\*+([^*/][^*]*\*+)*/|\#.*|--.*|[^"\'?#])+%u', function($match) use($binding, &$count) {
if($match[0] == '?' && isset($binding[++$count])) {
return $binding[$count];
} else {
return $match[0];
}
},  $query, -1, $count);

Хорошие результаты:

SELECT * FROM table WHERE a = ':bar \\\' :bar \' :bar \' :bar \\\' :bar' OR b = ':bar \\\" :bar \" :bar \" :bar \\\" :bar' OR foo = :foo AND fooo = :foo_o AND bar = :bar
SELECT * FROM table WHERE a = ':bar \\\' :bar \' :bar \' :bar \\\' :bar' OR b = ':bar \\\" :bar \" :bar \" :bar \\\" :bar' OR foo = nice AND fooo = good AND bar = owned

SELECT * FROM table WHERE a = '? \\\' ? \' ? \' ? \\\' ?' OR '? \\\" ? \" ? \" ? \\\" ?' OR foo = ? AND fooo = ? AND bar = ?
SELECT * FROM table WHERE a = '? \\\' ? \' ? \' ? \\\' ?' OR '? \\\" ? \" ? \" ? \\\" ?' OR foo = *1 AND fooo = 2*? AND bar = lol

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …