【问题标题】:PHP - How to capture only one string between delimiters from multiline strings based on defined positionPHP - 如何根据定义的位置从多行字符串的分隔符之间仅捕获一个字符串
【发布时间】:2018-02-23 18:06:57
【问题描述】:

我有一个小的网络 sql 编辑器,但是当用户编写如下查询时:

SELECT * FROM users;
SELECT * FROM references;|  <-- here is the caret, i want to run only this query
SELECT * FROM settings

并提交该字符串,仅执行第一个查询。我只想运行用户插入符号所在的查询。

显然,该示例看起来很简单,但请考虑在真实环境中使用更真实的查询,例如:

SELECT col1,col2,col3
FROM users
WHERE id IN (1,2,3,4);
SELECT * FROM references WHERE status = 1
;
SELECT 
    a.col1
    , a.col2
    , b.col1 
FROM table_a a |                            <--- Here is the caret, run this query
    INNER JOIN table_b b ON b.id_table_a = a.id
WHERE a.id = 5
;
UPDATE table_a SET col1 = 'demo' WHERE id = 3;
-- etc, etc, etc

到目前为止,我有插入符号的位置:行和列,并将字符串分成两部分:插入符号之前和插入符号之后。 然后我在第一个字符串的最后一个分号出现之后得到子字符串,在第二个字符串第一次出现之前得到子字符串。

但我想知道是否有其他方法可以更有效地解决这个问题。

【问题讨论】:

  • 您允许您的用户执行任意 SQL 语句? (我知道正则表达式问题的题外话。只是好奇。)
  • 那种...这个工具仅用于测试,类似于 PHPMyAdmin,但用于教学目的...并且某些查询被 dbuser 权限阻止
  • 我认为,您不应该以; 作为分隔符来缩小自己的范围,因为可能需要更改它。

标签: php regex delimiter multiline


【解决方案1】:

试试这样的正则表达式: /(?&lt;=;)(.*)(?=\|)/

【讨论】:

  • 我用这个字符串试过了:SELECT;UPDATE|query;INSERT; 并且只得到 UPDATE 部分......并且预期是 UPDATE 查询,但我喜欢这种方法。
  • 试试这个:/(?&lt;=;)(.*?\|.*?)(?=;)/ 这会在查询中的任何位置获取管道,但您需要在匹配后替换管道才能将其从那里取出。我认为有一种方法可以忽略它。我不确定我的头顶,但也许其他人会。我会调查的
【解决方案2】:

您可以为此使用正则表达式或非正则表达式方法。如果您的查询将在其中包含 |(管道),那么指定一个不同/唯一的标记会更合适。

代码:(Demo)

$queries="
SELECT col1,col2,col3
FROM users
WHERE id IN (1,2,3,4);
SELECT * FROM references WHERE status = 1
;
SELECT 
    a.col1
    , a.col2
    , b.col1 
FROM table_a a |                            <--- Here is the caret, run this query
    INNER JOIN table_b b ON b.id_table_a = a.id
WHERE a.id = 5
;
UPDATE table_a SET col1 = 'demo' WHERE id = 3;
-- etc, etc, etc";

$rtrimmed=substr($queries,0,strpos($queries,'|'));     // remove substr following pipe
$ltrimmed=substr($rtrimmed,strrpos($rtrimmed,';')+1);  // remove substr upto latest semicolon
echo trim($ltrimmed);                                  // remove whitespace on either side

echo "\n---\n";

echo preg_match('~;\s*\K[^;|]*?(?= *\|)~',$queries,$out) ? $out[0] : '';

输出:

SELECT 
    a.col1
    , a.col2
    , b.col1 
FROM table_a a
---
SELECT 
    a.col1
    , a.col2
    , b.col1 
FROM table_a a

Pattern Demo

模式细分:

~         #pattern delimiter
;\s*      #match semicolon followed by zero or more whitespace characters
\K        #restart the fullstring match (release previous matched characters)
[^;|]*?   #match zero or more (lazily) non-semicolon and non-pipe characters
(?= *\|)  #look ahead for zero or more spaces followed by a pipe (so that the output is trimmed)
~         #pattern delimiter

【讨论】:

    猜你喜欢
    • 2019-06-24
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    • 2011-08-22
    • 2013-10-19
    • 1970-01-01
    • 2016-12-08
    相关资源
    最近更新 更多