-
示例 1
考虑一下这段简单的代码。
<script>
<?php $myVarValue = 'hello world'; ?>
var myvar = <?php echo json_encode($myVarValue); ?>;
alert(myvar);
</script>
输出:
<script>
var myvar = "hello world";
alert(myvar);
</script>
它会提醒hello world。 很好。
-
示例 2
让我们尝试将</script> 作为字符串。
<script>
<?php $myVarValue = '</script>'; ?>
var myvar = <?php echo json_encode($myVarValue); ?>;
alert(myvar);
</script>
输出:
<script>
var myvar = "<\/script>";
alert(myvar);
</script>
它会提醒</script>。 很好。
如您所见,斜线 (/) 正确转义为 \/,
-
示例 3
现在,考虑这个非常特殊的字符串:<!--<script>
<script>
<?php $myVarValue = '<!--<script>'; ?>
var myvar = <?php echo json_encode($myVarValue); ?>;
alert(myvar);
</script>
输出:
<script>
var myvar = "<!--<script>";
alert(myvar);
</script>
令人惊讶的是,它不会发出任何警报,并且错误控制台中也没有任何内容。 什么?!
如果您检查 JSON 的规范,<!--<script> 中的所有字符都不需要转义,那么出了什么问题?
图片改编自json.org
如需完整且解释清楚的答案,请阅读this amazing Q & A。简而言之,事实证明,
<script> 块中的 <!--<script> 会混淆 HTML 解析器。 PHP 实际上在json_encode() 中正确地完成了它的工作;
你不能在那里有<!--<script>,即使它是一个完全有效的 JavaScript 字符串!
我自己做了一些简单的测试。浏览器实际上会忽略<!--<script> 之后的所有内容,所以如果它发生在页面中间,
整个页面的后半部分消失了!我不确定是否有人真的可以在那里注入恶意的东西,比如说,任意执行
代码,但这已经够糟糕了。
还有,
- 如果
$myVarValue 中不仅有一个字符串,还有像array("key" => array("one", "and<!--<script>two", 3)) 这样的复杂对象,其中包括<!--<script>,那还是很糟糕。
- 如果您有一个纯 HTML 文件(即没有 PHP),并且在您的
<script> 块中的任何位置(甚至在 JavaScript 注释中)都有 <!--<script>,那也很糟糕。
- 如果您使用其他非 PHP 的服务器端编程语言并生成
<!--<script>,那也很糟糕。
- 如果你的 PHP 是直接输出 JavaScript (
Content-type: application/javascript),其实没问题[1]。
解决方案?使用JSON_HEX_TAG 转义< 和>(需要PHP 5.3.0)。
<script>
<?php $myVarValue = '<!--<script>'; ?>
var myvar = <?php echo json_encode($myVarValue, JSON_HEX_TAG); ?>;
// ^^^^^^^^^^^^^^
alert(myvar);
</script>
输出:
<script>
var myvar = "\u003C!--\u003Cscript\u003E";
alert(myvar);
</script>
它会提醒<!--<script>。 万岁!
之所以有效,是因为输出中不再有<!--<script>,因此不再存在 HTML 解析问题。
注意:如果您不打印到<script> 块中,则不需要JSON_HEX_TAG。
[1] 在这里,“ok”仅仅意味着它没有<!--<script> 问题。不建议动态生成外部 JavaScript 文件,因为它有很多缺点,例如 here、here、here 中的那些。
关于问题2:初始页面加载时间
实际上,这很明显。如果获取$myVarValue的值所需要的时间较长
(例如,您正在从数据库中获取大量数据),PHP 将不得不等待,浏览器和用户也是如此。
这意味着更长的初始页面加载时间。如果您稍后使用 Ajax 加载数据,它们将没有
等待看到初始结果,但是,Ajax 调用将是一个额外的 HTTP 请求,所以它
意味着更多的服务器工作负载,以及更多的网络负载。
当然,每种方法都有其优点和缺点,因此您必须做出决定。我建议阅读this excellent Q & A。