将一个 PHP 变量传递给一个 JavaScript 变量。

402
什么是将PHP字符串编码为JavaScript变量输出的最简单方法?
我有一个包含引号和换行符的PHP字符串。我需要将此字符串的内容放入JavaScript变量中。
通常,我会在PHP文件中构建我的JavaScript,如下所示:
<script>
  var myvar = "<?php echo $myVarValue;?>";
</script>

然而,当$myVarValue包含引号或换行符时,这种方法就不起作用了。


2
只是想指出,在将字符串传递给 json_encode 之前,您可以使用 utf8_encode()。这就是我正在做的:echo json_encode(utf8_encode($msg)); - carlosvini
1
这不是 https://dev59.com/C2Ag5IYBdhLWcg3wU5gS 的重复。后者涉及 AJAX 等网络问题,而这里涉及编码/转义/引号和换行符。我们重新开放吧?(顺便说一句,这里的被接受答案简短、有效,并且有很多投票) - Basj
14个回答

559

在别人的答案基础上进行扩展:

<script>
  var myvar = <?= json_encode($myVarValue, JSON_UNESCAPED_UNICODE); ?>;
</script>

使用 json_encode() 需要:

  • PHP 5.2.0 或更高版本
  • $myVarValue 编码为 UTF-8(或 US-ASCII,当然也可以)

由于 UTF-8 支持完整的 Unicode,因此在转换时应该是安全的。

请注意,如果您将其用于像 onclick 这样的 html 属性中,则需要将 json_encode 的结果传递给 htmlspecialchars(),如下所示:

htmlspecialchars(json_encode($string), ENT_QUOTES);

否则,您可能会遇到问题,例如,在foo()&amp;&bar;中的&bar;被解释为HTML实体。

10
如果您使用UTF-8,那将是目前最佳的解决方案。 - Kornel
4
重要的是在json_encode实现中转义正斜杠。如果没有这样做,那么如果$myVarValue为"</script>",则此代码将无法正常工作。但是json_encode确实转义了正斜杠,所以我们很好。 - Drew LeSueur
6
请注意,如果您在onclick属性等中使用此代码,则需要将json_encode的结果传递给htmlspecialchars,如下所示:htmlspecialchars(json_encode($string),ENT_QUOTES,'utf-8'),否则您可能会遇到问题,例如,在foo()&&bar;中的&bar;被解释为HTML实体。 - user2428118
如果字符串包含换行符,则我认为它会抛出一个错误。 - Abhisek Malakar
4
@hakre问道:但是,当PHP字符串包含"...</script>..."时,在PHP的json_encode之后,它如何变成JS非字符串</script>,而不仅仅是JS字符串"...</script>..."?它总是为字符串添加引号。因此,var x = "...</script>...";只是一个JS字符串。不会中断。回答:PHP字符串包含"...</script>..."时,在PHP的json_encode之后,它将保持为JS字符串,即"...</script>...",并添加引号。因此,var x = "...</script>...";是一个JS字符串,不会中断。 - FlameStorm
显示剩余10条评论

27

使用JSON进行编码


可能是让这个工作100%正常运行的最简单方法。否则,要考虑的情况太多了。 - willasaywhat
Json 只能使用 UTF-8 字符集。因此,如果您的网站使用非 UTF-8 编码,则 Json 不是解决方案。 - Nir
4
一方面,我不知道为什么要使用其他编码方式;另一方面,完整的JSON编码器也可以处理任何必要的字符集转换。 - Javier
仅仅使用JSON进行编码是不够的,你还必须确保任何包含</script>(不区分大小写)的Javascript字符串得到适当处理。 - Flimm
我唯一的顾虑是使用json编码会将其强制转换为一个对象。在实践中,这更容易理解,但当涉及到复杂的数据数组,特别是从数据库中读取SQL结果时,程序员需要更深入的Javascript知识来有效地处理数据。本质上,我的意思是提供一个使用场景示例会很好。 - Christopher 'Solidus' DeJong
2
使用JSON编码单个标量值不会强制将其转换为对象 - 您只会得到一个utf-8字符串。例如,假设您的php代码如下:$x="<script>alert('xss!');</script>";而您的HTML如下:<script>var x=<?= json_encode($x);?></script>在浏览器中的结果将是:<script>var x="<script>alert('xss!');</script>"</script>请注意双引号和转义斜杠。 - Craig Jacobs

24
function escapeJavaScriptText($string)
{
    return str_replace("\n", '\n', str_replace('"', '\"', addcslashes(str_replace("\r", '', (string)$string), "\0..\37'\\")));
}

我需要这个是因为我正在使用变量的内容作为连接的JavaScript表达式的一部分。 - Phil Cairns
这确实帮了我很多。 - Austin

22

我曾经遇到过类似的问题,并了解以下是最佳解决方案:

<script>
    var myvar = decodeURIComponent("<?php echo rawurlencode($myVarValue); ?>");
</script>

然而,micahwittman发布的链接表明存在一些小的编码差异。PHP的rawurlencode()函数应该符合RFC 1738的规定,而Javascript的decodeURIComponent()并没有这样的努力。


decodeURIComponent 符合 RFC 3986 标准,我相信。 - Ry-
当你解析大型字符串(例如:将html内容作为字符串)时,这是正确的解决方案。 - Radu Gheorghies
@RaduGheorghies 为什么? - Tuesdave

12

谨慎的做法: 转义每个字符.

function javascript_escape($str) {
  $new_str = '';

  $str_len = strlen($str);
  for($i = 0; $i < $str_len; $i++) {
    $new_str .= '\\x' . sprintf('%02x', ord(substr($str, $i, 1)));
  }

  return $new_str;
}

编辑:json_encode() 可能不适合的原因是有时需要防止生成 ",例如:

<div onclick="alert(???)" />

转义每个字符对我很有效。json_encode 对反斜杠的处理不是很好。如果您需要将类似正则表达式的内容从 mysql 作为参数传递到 javascript,则这似乎是最佳方法。 - Ekim
@kristoffer-ryhl 正确指出dechex无法处理'\t' (= '\x08'),所以我对其进行了编辑以使用sprintf。然而,这似乎仍无法处理UTF-8字符(这需要使用'\u'代替)... - giraff
对于 HTML 属性,您可以使用以下代码:<div onclick="alert(<?php echo htmlspecialchars(json_encode($var));?>" /> - Flimm
这不是Unicode保存,请查看此链接:https://docs.laminas.dev/laminas-escaper/escaping-javascript/ - vinsa

6
<script>
var myVar = <?php echo json_encode($myVarValue); ?>;
</script>

或者

<script>
var myVar = <?= json_encode($myVarValue) ?>;
</script>

1
你不应该将编码后的值用引号括起来。 - Salman A
请注意,json_encode会转义正斜杠,这意味着它永远不会意外地打印出</script> - Flimm
与4年前的被接受答案有何不同? - Your Common Sense

4

Micah的解决方案对我非常有用,因为我需要定制的网站不是UTF-8编码,所以我不能使用json。我想给他投票,但我的声望还不够高。

function escapeJavaScriptText($string) 
{ 
    return str_replace("\n", '\n', str_replace('"', '\"', addcslashes(str_replace("\r", '', (string)$string), "\0..\37'\\"))); 
} 

我也是!这两行代码是发生在 PHP 中最好的事情(至少在我看来)。非常感谢!! - rizalp1

3
您可以将其插入到隐藏的DIV中,然后将该DIV的innerHTML赋值给JavaScript变量。您不必担心任何转义问题,但请确保不要在其中放置损坏的HTML代码。

“不要放入破碎的HTML”,这意味着转义“HTML实体”(至少包括'<'和'&')。 - Javier
不要过早关闭你的容器 DIV。 - Diodeus - James MacFarlane

3
  1. Don’t. Use Ajax, put it in data-* attributes in your HTML, or something else meaningful. Using inline scripts makes your pages bigger, and could be insecure or still allow users to ruin layout, unless…

  2. … you make a safer function:

    function inline_json_encode($obj) {
        return str_replace('<!--', '<\!--', json_encode($obj));
    }
    

我非常确定在脚本块中不需要转义 <!--,在有效的 Javascript 字符串文字中唯一需要注意的是 </script>,而 json_encode 从不输出它,因为它会转义正斜杠。 - Flimm
@Flimm:你看了codepad链接吗?试试<script>console.log("<!--<script>")</script><script>console.log(")/;alert('execute arbitrary code here');<!---->")</script>,其中传递给console.log的两个字符串是用户提供的(即模板看起来像<script>console.log({{ s1 }})</script><script>console.log({{ s2 }})</script>,其中$s1$s2来自一个糟糕的JSON编码器)。尽管第二个字符串包含一个未转义的正斜杠,而且这个例子完全是虚构的,但是恶意用户仍然可以造成这样的语法错误。 - Ry-
@Flimm:这是如何工作的:“<!--<script>-->”会导致合法的“</script>”被视为代码而不是结束标签。 - Ry-

3

不要在代码中使用addslashes()方法;如果你处于HTML页面的上下文中,HTML解析器仍然可以看到</script>标签,即使它出现在字符串中间,也会认为这是JavaScript的结束:

<?php
    $value = 'XXX</script><script>alert(document.cookie);</script>';
?>

<script type="text/javascript">
    var foo = <?= json_encode($value) ?>; // Use this
    var foo = '<?= addslashes($value) ?>'; // Avoid, allows XSS!
</script>

也许我犯了一个愚蠢的错误,但是当我尝试执行这段代码时,只有在引用外部.js文件时才会出现以下控制台错误SyntaxError: expected expression, got '<',而当它是内联的时候,它可以正常工作。你有什么想法? - Ryan Dorn
@RADMKT 只是猜测,但如果它是一个 .js 文件,它可能不使用 PHP。值得在 Web 浏览器中加载外部 JS 文件以查看代码输出。 - Craig Francis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接