5

我有一个混合了 HTML 的 php 页面。一些示例代码:

<?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 标记处拆分,但保留引号或注释中的任何 PHP 标记或 HTML 标记不变/忽略。这是我到目前为止所拥有的:

$array = preg_split("/((^<\?php)|([^'|\"]<\?php)|([^'|\"]<\?)|([^'|\"]\?>)|(<\%)|(\%>))/i", $string, -1);

我遇到的问题是最终 $array 中缺少一些 HTML 右括号“>”。我想保持 HTML 打开和关闭标签完好无损。有时我最终得到

<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 不将它们视为任何分隔符并忽略它们中的任何一个。

我也刚刚意识到一些 php 标签,尤其是在使用 eval() 时可能会像这样结束:

"?> <p>some HTML text</p> <?";

这意味着我的正则表达式中的引用与任何这些情况都不匹配。

Preg_match() 可能是一个更好的选择,但不确定。

任何帮助都将不胜感激,因为我在正则表达式方面不是很聪明,而且在这一点上陷入了困境。

非常感谢 :)

4

1 回答 1

2

前言
由于提出了正则表达式解决方案,因此以下解决方案将依赖于正则表达式。但是,在这种特殊情况下,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

第 1 行我使用这个正则表达式分隔符,因为它允许避免 /
第 2 行的转义这是正则表达式的关键。否定的lookbehind用于确保下一个开始的php标签前面没有任何单引号或双引号。
第 3 行这里定义了一个开始的 php 标记是什么。为了也支持 ASP 标签,这行可以这样修改:<\\?(?:php|%)?\\s+
第 4 行因为我们检测到一个 php 代码序列的开始,我们匹配这个 php 代码序列中出现的任何字符。请注意,在第 9 行,我们使用s标志来指示我们在 php 代码序列中也需要新行。
第 5 行我们标记了 php 代码序列的结束。
第 6 行我们确保前面匹配的 php 标记后面没有任何带有否定前瞻断言的单/双引号。
第 7,8 行如果我们发现一些 php/HTML 注释,它们将被简单地忽略。
第 9 行结束 f 正则表达式。

已知的问题

  • 在 上执行正则表达式后$subject,行简单地用换行符(前面是可选的回车符)分隔符分隔。
  • 不努力处理 php heredoc 或 newdoc 语法。
  • 此正则表达式不应视为针对任何 php 代码的防弹正则表达式。PHP 解析器更适合。
于 2012-12-03T16:31:39.663 回答