我有一个变量在PHP,我需要它的值在我的JavaScript代码。我怎么能把我的变量从PHP到JavaScript?

我有这样的代码:

<?php
$val = $myService->getValue(); // Makes an API and database call

在同一页上,我有JavaScript代码,需要$val变量的值作为参数传递:

<script>
    myPlugin.start($val); // I tried this, but it didn't work
    <?php myPlugin.start($val); ?> // This didn't work either
    myPlugin.start(<?=$val?>); // This works sometimes, but sometimes it fails
</script>

当前回答

我假设要传输的数据是一个字符串。

正如其他评论者所述,AJAX是一种可能的解决方案,但缺点大于优点:它有延迟,并且更难编程(它需要代码来检索服务器端和客户端值),而更简单的转义函数应该就足够了。

所以,我们又回到了逃避。如果您首先将源字符串编码为UTF-8, json_encode($string)就可以工作,因为json_encode需要UTF-8数据。如果字符串在ISO-8859-1中,那么您可以简单地使用json_encode(utf8_encode($string));否则,你总是可以先使用iconv来进行转换。

但这里有个大问题。如果你在事件中使用它,你需要在结果上运行htmlspecialchars(),以使它成为正确的代码。然后,您必须小心使用双引号将事件括起来,或者始终将ENT_QUOTES添加到htmlspecialchars中。例如:

<?php
    $myvar = "I'm in \"UTF-8\" encoding and I have <script>script tags</script> & ampersand!";
    // Fails:
    //echo '<body onload="alert(', json_encode($myvar), ');">';
    // Fails:
    //echo "<body onload='alert(", json_encode($myvar), ");'>";
    // Fails:
    //echo "<body onload='alert(", htmlspecialchars(json_encode($myvar)), ");'>";

    // Works:
    //echo "<body onload='alert(", htmlspecialchars(json_encode($myvar), ENT_QUOTES), ");'>";
    // Works:
    echo '<body onload="alert(', htmlspecialchars(json_encode($myvar)), ');">';

    echo "</body>";

然而,你不能在常规JavaScript代码上使用htmlspecialchars(代码包含在<script>…> < /脚本标签)。这使得使用这个函数容易出错,在编写事件代码时忘记htmlspecialchars结果。

可以编写一个不存在该问题的函数,并且可以在事件和常规JavaScript代码中使用,只要始终用单引号或双引号括起事件。以下是我的建议,要求它们在双引号中(我更喜欢这样):

<?php
    // Optionally pass the encoding of the source string, if not UTF-8
    function escapeJSString($string, $encoding = 'UTF-8')
    {
        if ($encoding != 'UTF-8')
            $string = iconv($encoding, 'UTF-8', $string);
        $flags = JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_UNESCAPED_SLASHES;
        $string = substr(json_encode($string, $flags), 1, -1);
        return "'$string'";
    }

该函数需要PHP 5.4+。使用示例:

<?php
    $myvar = "I'm in \"UTF-8\" encoding and I have <script>script tags</script> & ampersand!";
    // Note use of double quotes to enclose the event definition!
    echo '<body onload="alert(', escapeJSString($myvar), ');">';
    // Example with regular code:
    echo '<script>alert(', escapeJSString($myvar), ');</script>';
    echo '</body>';

其他回答

经过大量的研究,我发现最简单的方法是简单地传递各种变量。

在服务器脚本中,你有两个变量,你试图将它们发送到客户端脚本:

$php_var1 ="Hello world";
$php_var2 ="Helloow";
echo '<script>';
echo 'var js_variable1= ' . json_encode($php_var1) . ';';
echo 'var js_variable2= ' . json_encode($php_var2) . ';';
echo '</script>';

在页面上调用的任何JavaScript代码中,只需调用这些变量。

我通常在HTML中使用data-*属性。

<div
    class="service-container"
    data-service="<?= htmlspecialchars($myService->getValue()) ?>"
>

</div>

<script>
    $(document).ready(function() {
        $('.service-container').each(function() {
            var container = $(this);
            var service = container.data('service');

            // Var "service" now contains the value of $myService->getValue();
        });
    });
</script>

这个例子使用了jQuery,但是它可以用于其他库或普通JavaScript。

你可以在这里阅读更多关于dataset属性的信息:https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement.dataset

myPlugin.start($val); // Tried this, didn't work

它不起作用,因为就JavaScript而言,$val是未定义的,即PHP代码没有为$val输出任何东西。试着在浏览器中查看源代码,下面是你将看到的:

myPlugin.start(); // I tried this, and it didn't work

And

<?php myPlugin.start($val); ?> // This didn't work either

这并不管用,因为PHP将尝试将myPlugin视为常量,当失败时,它将尝试将其视为字符串'myPlugin',它将尝试与PHP函数start()的输出连接,由于这是未定义的,它将产生一个致命的错误。

And

 myPlugin.start(<?=$val?> // This works sometimes, but sometimes it fails

虽然这是最有可能工作的,因为PHP代码生成了带有预期参数的有效JavaScript,但如果失败,很可能是因为myPlugin还没有准备好。检查你的执行顺序。

您还应该注意到,PHP代码输出是不安全的,应该使用json_encode()进行过滤。

EDIT

因为我没有注意到myPlugin.start(<?=$val?>: \

正如@Second Rikudo指出的那样,要正确工作,$val需要包含右括号,例如:$val="42);"

这意味着PHP现在将生成myPlugin.start(42);并在JavaScript代码执行时按预期工作。

PHP

$fruits = array("apple" => "yellow", "strawberry" => "red", "kiwi" => "green");
<script>
    var color = <?php echo json_encode($fruits) ?>;
</script>
<script src="../yourexternal.js"></script>

JS (yourexternal.js)

alert("The apple color is" + color['apple'] + ", the strawberry color is " + color['strawberry'] + " and the kiwi color is " + color['kiwi'] + ".");

输出

苹果是黄色的,草莓是红色的,猕猴桃是红色的 颜色是绿色。

我想尝试一个更简单的答案:

问题的解释

首先,让我们了解当一个页面从我们的服务器被服务时的事件流:

首先运行PHP,它生成提供给客户端的HTML。 然后,当HTML被交付给客户端时,PHP“死亡”(即它字面上停止运行)。我要强调的是,一旦代码离开服务器,PHP就不再是页面加载的一部分,服务器也不再有对它的访问权。 然后,当带有JavaScript的HTML到达客户端时,客户端可以在该HTML上执行JavaScript,前提是它是有效的JavaScript。

这里要记住的核心是HTTP是无状态的。一旦请求离开服务器,服务器就不能接触它。所以,我们的选择是:

在初始请求完成后,从客户端发送更多请求。 编码服务器在初始请求中必须说的内容。

解决方案

这是你应该问自己的核心问题:

我是在写网站还是应用程序?

网站主要是基于页面的,页面加载时间需要尽可能快(例如-维基百科)。Web应用程序使用AJAX较多,需要执行大量往返以快速获取客户端信息(例如—股票仪表板)。

网站

在初始请求完成后从客户端发送更多的请求会很慢,因为它需要更多的HTTP请求,这有很大的开销。此外,它需要异步性,因为发出一个AJAX请求需要一个处理程序来处理它何时完成。

除非您的站点是用于从服务器获取信息的应用程序,否则我不建议您再次发出请求。

你需要快速的响应时间,这对转换和加载时间有很大的影响。在这种情况下,Ajax请求的初始正常运行时间较慢,而且是不必要的。

你有两种方法来解决这个问题

设置cookie - cookie是在HTTP请求中发送的报头,服务器和客户端都可以读取。 将变量编码为JSON——JSON看起来非常接近JavaScript对象,大多数JSON对象都是有效的JavaScript变量。

设置cookie并不难,你只需要给它赋一个值:

setcookie("MyCookie", $value); // Sets the cookie to the value, remember, do not
                               // Set it with HTTP only to true.

然后,你可以使用document.cookie用JavaScript读取它:

这是一个简短的手动解析器,但我链接到上面的答案有更好的测试:

var cookies = document.cookie.split(";").
    map(function(el){ return el.split("="); }).
    reduce(function(prev,cur){ prev[cur[0]] = cur[1]; return prev },{});
alert(cookies["MyCookie"]); // Value set with PHP.

cookie用于保存少量数据。这就是跟踪服务经常做的事情。

一旦我们有了更多的数据,我们可以用JSON在JavaScript变量中进行编码:

<script>
    var myServerData = <?=json_encode($value)?>; // Don't forget to sanitize
                                                 //server data
</script>

假设$value在PHP端是json_encodeable的(通常是)。这项技术就是Stack Overflow在它的聊天中所做的(只是使用。net而不是PHP)。

应用程序

如果你正在编写一个应用程序——突然之间,初始加载时间就不总是像应用程序的持续性能那么重要了,并且开始将数据和代码分开加载。

我在这里的回答解释了如何在JavaScript中使用AJAX加载数据:

function callback(data){
    // What do I do with the response?
}

var httpRequest = new XMLHttpRequest;
httpRequest.onreadystatechange = function(){
    if (httpRequest.readyState === 4) { // Request is done
        if (httpRequest.status === 200) { // successfully
            callback(httpRequest.responseText); // We're calling our method
        }
    }
};
httpRequest.open('GET', "/echo/json");
httpRequest.send();

或者使用jQuery:

$.get("/your/url").done(function(data){
    // What do I do with the data?
});

现在,服务器只需要包含一个/your/url路由/文件,其中包含抓取数据并对其进行处理的代码,在你的例子中:

<?php
$val = myService->getValue(); // Makes an API and database call
header("Content-Type: application/json"); // Advise client of response type
echo json_encode($val); // Write it to the output

这样,我们的JavaScript文件请求数据并显示它,而不是要求代码或布局。这样更干净,并且随着应用程序的提高,效果开始显现。它还可以更好地分离关注点,并且允许在不涉及任何服务器端技术的情况下测试客户端代码,这是另一个优点。

附言:当您将任何东西从PHP注入到JavaScript时,您必须非常注意XSS攻击向量。正确地转义值是非常困难的,而且它是上下文敏感的。如果您不确定如何处理XSS,或者不知道它——请阅读这篇OWASP文章,这篇文章和这个问题。