preg_split 混合 HTML 和 PHP 标记,引号和注释除外
Posted
技术标签:
【中文标题】preg_split 混合 HTML 和 PHP 标记,引号和注释除外【英文标题】:preg_split mixed HTML and PHP tags except in quotes and comments 【发布时间】:2012-11-17 06:04:07 【问题描述】:<?php echo "<p>some text</p>"; ?>/* <? some php in comments ?> */
<p>some HTML text</p> <!-- <h1>some HTML in comments</h1> -->
<? $header_info = <<<END
\$some="<?php @ob_start(); @session_set_save_handler(); ?>";
END; ?>
<h2>Some more HTML</h2>
我想在每个 PHP 和 HTML 标记处拆分,但保留引号或 cmets 中的任何 PHP 标记或 HTML 标记不变/忽略。这是我目前所拥有的:
$array = preg_split("/((^<\?php)|([^'|\"]<\?php)|([^'|\"]<\?)|([^'|\"]\?>)|(<\%)|(\%>))/i", $string, -1);
我遇到的问题是最终 $array 中缺少一些 HTML 右括号“>”。我想保持 HTML 打开和关闭标签完好无损。有时我会得到 p>
<p></p instead of <p></p>
应该是这样的:
[0] echo "<p>some text</p>";
[1] <p>some HTML text</p>
[2] $header_info = <<<END
\$some="<?php @ob_start(); @session_set_save_handler(); ?>";
END;
[3] <h2>Some more HTML</h2>
只要 preg_split 不将它们视为任何分隔符并忽略其中任何一个,任何 cmets 都不需要是数组的一部分。
我也刚刚意识到一些 php 标签,尤其是在使用 eval() 时可能会像这样结束:
"?> <p>some HTML text</p> <?";
这意味着我的正则表达式中的引号将不匹配任何这些情况。
Preg_match() 可能是更好的选择,但不确定。
任何帮助都将不胜感激,因为我在正则表达式方面不是很聪明,而且在这一点上卡住了。
非常感谢:)
【问题讨论】:
THE PONY HE COMES! - 只有在这里情况更糟,因为您还试图解析 PHP 块... 【参考方案1】:序言 由于询问了正则表达式解决方案,因此以下解决方案将依赖于正则表达式。然而,在这种特殊情况下,PHP 解析器会更适合。
正则表达式
#(?<!"|\')<\\?(?:php)?\\s+(.+?)\\?>(?!"|\')|/\*.+\*/|<!--.+-->#is
脚本
$subject = '<?php echo "<p>some text</p>"; ?>/* <? some php in comments ?> */
<p>some HTML text</p> <!-- <h1>some HTML in comments</h1> -->
<? $header_info = <<<END
\\$some="<?php @ob_start(); @session_set_save_handler(); ?>";
END; ?>
<h2>Some more HTML</h2>';
$returnValue = preg_replace('#(?<!"|\')<\\?(?:php)?\\s+(.+?)\\?>(?!"|\')|/\*.+\*/|<!--.+-->#is', '$1', $subject, -1);
var_dump(preg_split('#\\r?\\n#s', $returnValue));
结果
array(6)
[0]=>
string(25) "echo "<p>some text</p>"; "
[1]=>
string(22) "<p>some HTML text</p> "
[2]=>
string(21) "$header_info = <<<END"
[3]=>
string(60) "\$some="<?php @ob_start(); @session_set_save_handler(); ?>";"
[4]=>
string(5) "END; "
[5]=>
string(23) "<h2>Some more HTML</h2>"
演示http://sandbox.onlinephpfunctions.com/code/017a51877b50f272f151feade7b59e142757481e
讨论
1. #
2. (?<!"|\')
3. <\\?(?:php)?\\s+
4. (.+?)
5. \\?>
6. (?!"|\')
7. |/\*.+\*/
8. |<!--.+-->
9. #is
line 1 我使用这个正则表达式分隔符,因为它允许避免转义 /line 2 这是 key正则表达式。 negative lookbehind 用于确保下一个开始 php 标记前面没有任何单引号或双引号。第 3 行 这里定义了一个开始 php 标记是。为了也支持 ASP 标签,这一行可以这样修改:<\\?(?:php|%)?\\s+
第 4 行 因为我们检测到一个 php 代码序列的开始,我们匹配任何出现在这个 php 代码中的字符顺序。请注意,在 第 9 行,我们使用 s
标志来指示我们希望在 php 代码序列中也有新行。第 5 行我们标记 php 的结尾代码序列。第 6 行我们确保前面匹配的 php 标记后面没有任何带有 negative lookahead 断言的单引号/双引号。line 7,8 如果我们发现一些 php/HTML 注释,它们将被简单地忽略。line 9 结束 f 正则表达式。
已知问题
在$subject
上执行正则表达式后,只需使用换行符(前面有可选的回车符)分隔行。
不努力处理 php heredoc 或 newdoc 语法。
这个正则表达式应该不被视为针对任何 php 代码的防弹正则表达式。 PHP 解析器更适合。
【讨论】:
非常感谢 Stephan 非常详细的回答。我忘了提到处理任何类型的 php 代码输入是至关重要的。我想知道是否有人可以概述使用标记器的示例。提前致谢。我对 Tokenizer 不是很熟悉。我做了一些研究,发现了一些关于如何使用 PHP Tokenizer 从 PHP 中剥离 cmets 的代码,但很难理解代码。 您的代码应改为输出以下内容: [0]=>$subject = '<?php echo "<p>some text"; ?>'; /* cmets 中的一些 php ?> */ [1]=><p>一些 HTML 文本</p> <!-- <h1>cmets 中的一些 HTML</h1> --> [2]=>$header_info = ";结尾; ?> [3]="<h2>还有一些 HTML</h2> "
所以基本上我想在每个不在引号或 cmets 内的 php 标签和任何中间的 HTML 以它自己的数组键结束。丢失或保持 cmets 完好无损。
对不起,我试图格式化上面的代码,但它变得一团糟。这是我的第一篇文章。通读评论格式,但... @user1862374 我无法理解代码应该如何输出。您可以将其再次粘贴到您的问题中作为更新吗? Tks以上是关于preg_split 混合 HTML 和 PHP 标记,引号和注释除外的主要内容,如果未能解决你的问题,请参考以下文章