为什么会省略close标签?

时间:2010-12-10 16:00:39

标签: php security http-headers

我一直在阅读在文件末尾使用PHP关闭标记?>是不好的做法。标题问题在以下上下文中似乎无关紧要(这是迄今为止唯一的好参数):

  

现代版本的PHP在php.ini中设置了output_buffering标志   如果启用了输出缓冲,则可以在输出HTML后设置HTTP标头和cookie,因为返回的代码不会立即发送到浏览器。

每本好的练习册和维基都以这条“规则”开头,但没有人提供充分的理由。 还有另一个跳过结束PHP标记的好理由吗?

14 个答案:

答案 0 :(得分:306)

虽然我记不起任何其他原因,但是比正常课程更早发送标题可能会产生深远的影响。以下是我现在想到的其中一些:

  1. 虽然当前的PHP版本可能具有输出缓冲功能,但实际的生产服务器您将部署代码远比任何开发或测试机器重要。而且他们并不总是倾向于立即关注最新的PHP趋势。

  2. 您可能会因莫名其妙的功能丢失而感到头痛。比如说,您正在实施某种支付网关,并在支付处理器成功确认后将用户重定向到特定的URL。如果发生某种PHP错误,甚至是警告或多余的行结束,付款可能仍未处理,用户可能仍然看似未开单。这也是为什么不必要的重定向是邪恶的原因之一,如果要使用重定向,必须谨慎使用它。

  3. 即使在最新版本中,您也可能在Internet Explorer中收到“页面加载已取消”类型的错误。这是因为 AJAX 响应/ json包含了一些它不应该包含的内容,因为某些PHP文件中有多余的行结尾,就像我几天前遇到的那样。

  4. 如果你的应用中有一些文件下载,那么它们也会因此而中断。你可能不会注意到它,即使经过多年,因为下载的具体破坏习惯取决于服务器,浏览器,文件的类型和内容(以及可能还有其他一些我不想厌烦的因素)

  5. 最后,许多PHP框架包括SymfonyZend和Laravel(在coding guidelines中没有提到这一点,但它遵循诉讼)和{{3 (项目2.2)要求省略结束标记。 PHP手册本身(PSR-2 standard1),2Wordpress以及许多其他PHP软件,我建议这样做。如果您只是习惯遵循标准(并为您的代码设置Drupal),您可以忘记这个问题。否则你总是需要记住这个问题。

  6. 奖励:与这两个字符相关的一些问题(实际上是当前一个):

    1. 即使是一些知名的图书馆也可能在?>之后包含多余的行结尾。一个例子是Smarty,即使是最新版本的2. *和3. *分支都有这个。因此,与往常一样,关注第三方代码。额外奖励:删除不必要的PHP结尾的正则表达式:在包含PHP代码的所有文件中用空文本替换(\s*\?>\s*)$

答案 1 :(得分:117)

你应该放弃php结束标记(?>)的原因是程序员不会意外地发送额外的换行符。

你不应该放弃php结束标签的原因是因为它导致php标签的不平衡,任何半心半意的程序员都记得不能添加额外的空白区域。

所以对于你的问题:

  

是否有另一个很好的理由跳过结束的php标签?

不,没有另一个有理由跳过结束的php标记。

我将完成一些不打扰结束标记的论据:

  1. 无论多么聪明,人们总是会犯错误。 坚持减少可能出错的次数的做法是(恕我直言)一个好主意。

  2. PHP不是XML。 PHP不需要遵循XML严格的标准来编写和编写功能。如果丢失的结束标记让您烦恼,那么您可以使用结束标记,这不是一种固定的规则。

答案 2 :(得分:54)

这是新手编码风格推荐,善意,并建议by the manual

  • 避免?>只能解决常见的headers already sent causes(原始输出,BOM,通知等涓涓细流及其后续行为特写问题。

  • ?>结束令牌之后,PHP实际上包含一些魔术来消耗单行换行符。虽然有historic issues,但是新成员仍然容易受到片状编辑的影响,并且在?>之后在其他空白中无意中洗牌。

  • 在风格上,一些开发人员更喜欢将<?php?>视为SGML标记/ XML处理指令,这意味着尾随关闭标记的平衡一致性。 (对于依赖性连接类,哪个btw,是有用的包括取代低效率的逐个文件自动加载。)

  • 有点不常见的是,开放<?php被定义为PHP shebang (并且每binfmt_misc完全可行),从而验证了相应关闭标记的冗余。< / p>

  • classic PHP syntax guides强制要求?>\n与更多recent ones (PSR-2)同意遗漏之间存在明显的建议差异。
    (对于记录:Zend Framework假设一个在另一个上并不意味着它固有的优势。这是一种误解,专家被吸引到/目标受众的笨拙的API)。

  • SCMs和现代IDE provide builtin solutions主要是为了缓解贴身标签的护理。

不鼓励使用?>关闭标记只会延迟解释基本的PHP处理行为和语言语义,以避免不常见的问题。由于参与者的熟练程度变化,协作软件开发仍然是实用

关闭代码变体

  • 常规 &gt; 关闭标记也称为T_CLOSE_TAG,或称为“关闭令牌”

  • 它包含了更多的化身,因为PHP的神奇换行

    &gt; \ n (Unix换行)

    &gt; \ r (回车,经典MAC)

    &GT; \ r \ n (CR / LF,在DOS / Win上)

    然而,PHP不支持Unicode组合换行符 NEL (U + 0085)。

    早期的PHP版本有一些IIRC编译器在某种程度上限制了平台不可知性(FI甚至只使用>作为关闭标记),这可能是避免关闭标记的历史起源。

    < / LI>
  • 经常被忽略,但在PHP7 removes them之前,常规的 <?php 开场令牌可以有效与很少使用的 </script>奇数结算令牌

  • 硬关闭标签”甚至不是一个 - 只是将该术语作为类比。然而,在概念上和使用方面__halt_compiler应被视为近距离令牌。

    __HALT_COMPILER();
    ?>
    

    其中,令牌器基本上会丢弃任何代码或之后的纯HTML部分。特别是PHAR存根使用它,或者如图所示与?>的冗余组合。

  • 同样, void return; 在包含脚本中不经常替换,使任何?>的尾随空格无效。

  • 然后有各种 soft / faux 关闭标签变体;鲜为人知且很少使用,但通常每注释掉令牌:

    • 简单间距 // ? > 以逃避PHP标记器的检测。

    • 或者花哨的Unicode替代 // ﹖﹥ (U + FE56小问号,U + FE65小角度支架),正则表达式可以掌握。

    两者对PHP 无意义,但可以实际用于PHP-unaware或半知识外部工具包。再次考虑cat - 加入的脚本会产生// ? > <?php个连接,这些连接内联保留以前的文件切片。

因此,存在依赖于上下文但却是实用的替代方案,而这些替代方案必须采用必要的标签遗漏。

?>关闭标签的手动保姆不是很现代。总是有自动化工具(即使只是sed / awk或regex-oneliners)。特别是:

  

phptags tag tidier
  
  https://fossil.include-once.org/phptags/

对于第三方代码,通常可用于--unclose个php标记,或者只是修复任何(和所有)实际空白/ BOM问题:

  • phptags --warn --whitespace *.php

它还处理--long标记转换等,以实现运行时/配置兼容性。

答案 3 :(得分:21)

这不是标签......

但是,如果你拥有它,你可能会面临白色空间。

如果您将其用作文档顶部的包含,则在尝试发送HTTP标头之前,最终可能会插入空格(即内容)...这是不允许的。

答案 4 :(得分:15)

不要让结束?>进入。

非常有用

该文件对PHP保持有效(不是语法错误),并且@David Dorward说它允许在?>之后避免使用空格/断行(可以向浏览器发送标题的任何内容)

例如,

<?
    header("Content-type: image/png");
    $img = imagecreatetruecolor ( 10, 10);
    imagepng ( $img);
?>
[space here]
[break line here]

无效。

但是

<?
    header("Content-type: image/png");
    $img = imagecreatetruecolor ( 10, 10 );
    imagepng ( $img );

意愿。

一次,你必须懒得安全

答案 5 :(得分:13)

根据the docs,由于以下原因,如果它位于文件末尾,则最好省略结束标记:

  

如果文件是纯PHP代码,则最好省略文件末尾的PHP结束标记。这可以防止在PHP结束标记之后添加意外的空格或新行,这可能会导致不必要的影响,因为当程序员无意在脚本中发送任何输出时,PHP将启动输出缓冲。

PHP Manual > Language Reference > Basic syntax > PHP tags

答案 6 :(得分:9)

嗯,有两种方法可以看待它。

  1. PHP代码只不过是一组XML processing instructions,因此任何扩展名为.php的文件只不过是一个XML文件,恰好可以解析为PHP代码。
  2. PHP正好碰巧为其open和close标签共享XML处理指令格式。基于此,具有.php扩展名的文件可能是有效的XML文件,但它们不一定是。
  3. 如果您相信第一条路线,那么所有PHP文件都需要关闭结束标记。省略它们将创建无效的XML文件。再说一遍,没有开放<?xml version="1.0" charset="latin-1" ?>声明,你就不会有一个有效的XML文件......所以这不是一个主要的问题...

    如果您相信第二条路线,则会为两种.php文件打开大门:

    • 仅包含代码的文件(例如库文件)
    • 包含本机XML和代码(例如模板文件)的文件

    基于此,只有代码的文件可以在没有结束?>标记的情况下结束。但是,如果没有结束?>,XML代码文件就不能结束,因为它会使XML无效。

    但我知道你在想什么。你在想什么是重要的,你永远不会直接渲染PHP文件,所以谁在乎它是否是有效的XML。嗯,如果你正在设计一个模板,这很重要。如果它是有效的XML / HTML,普通浏览器将不会显示PHP代码(它被视为注释)。因此,您可以模拟出模板,而无需在...中运行PHP代码。

    我不是说这很重要。这只是一种我认为不太常见的观点,所以有更好的地方分享它......

    就个人而言,我不会关闭库文件中的标签,但会在模板文件中关闭...我认为这是个人偏好(和编码指南),而不是任何困难......

答案 7 :(得分:8)

嗯,我知道原因,但我无法证明:

  

对于仅包含PHP代码的文件,结束标记(?>)永远不会   允许的。 PHP不要求它,   并省略它可以防止   意外注入尾随白色   空间进入响应。

来源:http://framework.zend.com/manual/en/coding-standard.php-file-formatting.html

答案 8 :(得分:7)

除了已经说过的所有内容之外,我还要提出另一个原因,这对我们来说是一个巨大的痛苦。

Apache 2.4.6使用PHP 5.4,当关闭php标记后面有空白空间时,实际上我们的生产机器上存在分段错误。我只是浪费了几个小时,直到最后我用strace缩小了这个bug。

以下是Apache抛出的错误:

[core:notice] [pid 7842] AH00052: child pid 10218 exit signal Segmentation fault (11)

答案 9 :(得分:6)

“还有另一个好的理由(除了标题问题)跳过结束的php标签吗?”

生成二进制输出,CSV数据或其他非HTML输出时,您不希望无意中输出无关的空白字符。

答案 10 :(得分:5)

赞成

缺点

结论

我会说支持省略标记的论据看起来更强(有助于避免使用 header() +它的PHP / Zend“推荐”)。我承认这不是我在语法一致性方面见过的最“漂亮”的解决方案,但还有什么可以更好?

答案 11 :(得分:2)

由于我的问题被标记为此问题的副本,我认为它是O.K.发布为什么省略结束标记?>可能是出于某些原因。

  • 使用完整的处理指令语法(<?php ... ?>)PHP源代码是有效的SGML文档,可以在没有SGML解析器问题的情况下对其进行解析和处理。有了额外的限制,它也可以是有效的XML / XHTML。

没有什么能阻止您编写有效的XML / HTML / SGML代码。 PHP documentation意识到了这一点。摘录:

  

注意:另请注意,如果要在PHP或XHTML中嵌入PHP,则需要使用&lt; ?php?&gt;标签以保持符合标准。

当然,PHP语法并不严格SGML / XML / HTML,您创建的文档不是SGML / XML / HTML,就像您可以将HTML转换为符合XML的XHTML一样。

  • 在某些时候,您可能想要连接源。如果您通过省略关闭cat source1.php source2.php标记而引入不一致,那么这并不像简单地执行?>那么容易。

  • 如果没有?>,很难判断文档是否处于PHP转义模式或PHP忽略模式(PI tag <?php可能已打开或未打开)。如果您始终将文档保留在PHP忽略模式下,生活会更容易。与具有未封闭,嵌套严重的标签等的文档相比,它就像使用格式良好的HTML文档一样。

  • 似乎有些像Dreamweaver这样的编辑可能会遇到PI左开 [1]的问题。

答案 12 :(得分:0)

如果我正确理解了这个问题,那么它与输出缓冲以及这可能对结束/结束标记产生的影响有关。我不确定这是一个完全有效的问题。问题是输出缓冲区并不意味着所有内容在发送到客户端之前都保存在内存中。这意味着一些内容是。

程序员可以故意刷新缓冲区或输出缓冲区,因此PHP中的输出缓冲区选项真的会改变结束标记对编码的影响吗?我认为它没有。

也许这就是为什么大部分答案都回归个人风格和语法。

答案 13 :(得分:0)

有两种可能的PHP代码使用方法:

  1. PHP代码,例如类定义或函数定义
  2. 使用PHP作为模板语言(即在视图中)
  3. 如果情况1.结束标记完全无法使用,我也希望在这种情况下只看到1(一)个php打开标记和NO(零)结束标记。这是一个很好的做法,因为它使代码清晰并将逻辑与表示分开。 对于演示案例(2.),有些人发现关闭所有标签(甚至PHP处理的标签)是很自然的,这会导致混淆,因为PHP实际上有2个单独的用例,不应该混合使用:逻辑/微积分和演示文稿