Со стороны браузера пользователь будет вводить логический запрос, который может стать сложным, и я хочу преобразовать его в оператор SQL SELECT.
Пользователь введет текстовую строку, похожую на a AND ((b OR c) OR (not d)). Как я уже сказал, это произвольная текстовая строка, содержащая логическое выражение.
Это для рекрутера программного обеспечения, поэтому a, b, c, d и т. д. будут навыками, такими как C, C++, UML, Python и т. д., так что предыдущий пример может на самом деле читаться как C++ AND ((UML OR Python) OR (not Perl)).
Что я хочу расширить до (в данном случае) SELECT * FROM candidates WHERE skill=C++ AND ((skill=UML OR skill=Python) OR (not skill=Perl)).
Я могу добавить оператор SELECT, но как мне перевести (например) C++ AND ((UML OR Python) OR (not Perl)) в skill=C++ AND ((skill=UML OR skill=Python) OR (not skill=Perl)) и сделать это для любого произвольного логического выражения с любым количеством скобок в PHP?






Я сделал следующее наблюдение из приведенного вами примера: все, что вам нужно сделать, это заменить токены, такие как C++, на токен формы skill=C++, остальная часть запроса не изменится. Если это не всегда так, вам может понадобиться более сложное решение, но если вам этого достаточно, должно работать следующее:
$expr = 'C++ AND ((UML OR Python) OR (not Perl))';
// remove tokens that will not be replaced, here `(`, `)`, and `not`
$trimmed = str_replace(['(', ')', 'not'], ['', '', ''], $expr);
// split string based on the keywords `AND` and `OR` (case insensitive)
// keywords will also not be replaced
$tokens = preg_split('/AND|OR/i', $trimmed);
// create replacement tokens without leading/trailing whitespace
$replacementTokens = [];
foreach ($tokens as &$token) {
$token = trim($token);
$replacementTokens[] = "skill=$token";
}
// replace tokens and construct the query
$where = str_replace($tokens, $replacementTokens, $expr);
$query = "SELECT * FROM candidates WHERE $where";
Как уже говорилось, это решение может не сработать, если вам нужно более сложное поведение. Вам также может понадобиться расширить списки ключевых слов. Но для простого варианта использования, который вы предоставили, это позволяет избежать фактического анализа запроса.
И последнее замечание: убедитесь, что вы дезинфицируете пользовательский ввод, чтобы вы не были подвержены SQL-инъекциям.
Вы правы насчет пропущенных кавычек. Я просто взял ожидаемую строку из ответа. О SQL-инъекциях: в своем ответе я отметил опасность SQL-инъекций. Конечно, лучше всего было бы использовать подготовленные операторы, но они немного зависят от поставщика, и, поскольку в вопросе не упоминалась конкретная база данных, я не включил ее в свой ответ.
WHERE skill=C++). Но если вы исправите это с помощью"skill='$token'", тогда он будет открыт для SQL-инъекции (например,' union select pwd,0,0,0 from admins where '1).