【问题标题】:Execute javascript in PHP在 PHP 中执行 javascript
【发布时间】:2011-02-11 13:17:06
【问题描述】:

我正在使用 PHP 生成您的典型 Web 2.0 HTML 页面:它包含大量 <script> 标记和 javascript 代码,这些代码将在加载事件后显着改变 DOM。

有没有办法直接从 PHP 获取最终的 HTML 代码,而不用任何浏览器打开页面?

例如,假设页面的 HTML 是(这只是一个示例):

<html>
<head>
<script>...the jquery library code...</script>
<script>$(document).ready(function() { $("body").append("<p>Hi!</p>");</script>
</head>
<body>
</body>
</html>

此 HTML 保存在 $html PHP 变量中。现在,我想将该变量传递给某个函数,该函数将返回 $result = &lt;html&gt;....&lt;body&gt;&lt;p&gt;Hi!&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;

这可能吗?

编辑:由于你们中的许多人对我的要求感到困惑,我将解释原因。不幸的是,用户面对的一切都是用 javascript 制作的,这使得网站无法被搜索引擎抓取。所以我想改为向他们发送 post-ready 事件 HTML 代码。

【问题讨论】:

  • 听起来像是缺少渐进增强和非侵入式javascript的情况。通常可以使用 javascript 和不使用 javascript 来提供内容,因此如果有人没有打开 javascript,他们仍然可以访问该内容。
  • @John:当然,但它不是这样做的,现在改变它是令人望而却步的。
  • 那听起来你有很多工作要做。

标签: php javascript html


【解决方案1】:

使用 PHP 评估 JavaScript 代码,请查看 V8 JavaScript engine extension,您可以将其编译到您的 PHP 二进制文件中:

V8 是Google's open source JavaScript implementation

【讨论】:

    【解决方案2】:

    我能找到的最佳解决方案是在服务器上使用 HtmlUnit http://htmlunit.sourceforge.net/ 使用 javascript 执行您的 html 并取回用户将在浏览器上看到的最终 html。

    该库对 JavaScript 有很好的支持,并且是无头的,因此您应该能够在服务器上运行它。

    您需要编写一个小型 Java 包装器,该包装器可以通过命令行接受输入并将其传递给 HtmlUnit 进行处理,然后将结果返回给您。然后你可以从 PHP 调用这个包装器。

    【讨论】:

      【解决方案3】:

      你有两个问题:

      1. 执行 JavaScript。
      2. 更新DOM(执行javascript后的html)。

      要执行 javascript,您需要一个 javascript 引擎。目前有 3 个可供您使用:

      1. V8:谷歌浏览器。 PHP 扩展。
      2. Rhino:由 Mozilla 为 Firefox 提供。仅在 JAVA 中可用。
      3. JavaScriptCore:由 Apple 为 Safari 提供。仅在 C 中可用。

      一旦您拥有了 javascript 引擎,您就需要管理 DOM(文档对象模型)。这允许您将 HTML 解析为 DOM 节点、文本节点、元素等对象。最重要的是,您需要将 DOM 与 javascript 引擎同步并在 javascript 引擎中安装 DOM 库。虽然可能有多种方法可以做到这一点,但我更喜欢简单地将独立的 JavaScript DOM 包含/评估到引擎中,然后简单地将 HTML 传递给它。

      1. Env-JS JavaScript DOM 库。兼容原型/jQuery。
      2. jsdom NodeJS 的 JavaScript DOM 库。

      现在您拥有 JavaScript 引擎和 DOM 库,您现在可以毫无问题地评估大多数脚本。

      最佳答案

      NodeJS 是一个独立的可执行文件,它有一个 javascript 引擎以及 DOM 操作,所有这些都在 1 中。除此之外,您还可以将它用作 Web 服务器。也许这是解决您问题的更好方法,但是如果必须使用 PHP,请坚持上面提到的内容。

      【讨论】:

        【解决方案4】:

        这个问题和如何在javascript中执行javascript,或者php中的php非常相似,答案是可以eval。如果 php 可以 eval javascript 并且 javascript 可以 eval php,我们就不会有这个讨论了。

        为了让 JavaScript 评估 PHP,它必须将 PHP 代码解析为代表脚本的结构。 JavaScript 可以使用 JavaScript 对象表示法(不是 JSON 格式,而是实际表示)轻松地做到这一点,并在功能上分解脚本。

        这是一个 JavaScript 解释 PHP 的幼稚示例(更诚实的示例不会那么做作,而是将 php 解析为它自己的类似 JSON 的表示或可能的字节码,然后在 javascript 仿真上解释这个类似 json 的表示或字节码的php虚拟机,但仍然):

        (() => {
            'use strict';
        
            var phpSnippet = 'echo "Hi";';    
        
            var partialPHPEval = (phpCode) => {
                var regex = /echo[\s]["]([^"]*)["][;]/mg;
                var match = null;
                phpCode = phpCode.trim();
        
                if ((match = phpCode.match(regex))) {
                    var code = (match[0].replace(regex, "(console.log('$1'))"));
                    console.log('converted to "' + code + '"');
        
                    eval(code);
                }        
            };
        
            partialPHPEval(phpSnippet);  
        })();
        

        问题在于 PHP 不是 javascript,并且它的 eval 比 javascript 的弱得多。

        这会产生一个问题,即 php 可以轻松地发出将 javascript 标记为 PHP 的请求:JavaScript 可以轻松地创建任何东西的“JSON 化”版本(只要它不是本机的),因此您可以让 PHP 发送请求到带有您要评估的脚本的 nodejs 服务器。

        例如:(PHP代码)

        include "some_file_defining_jsEval.php";
        
        $wantedObject = function($a) {
            return $a;
        };
        
        $resultingObject = jsEval(
            '(function(a) {' .
            '    return a;' .
            '})'
        );
        
        echo $resultingObject("Hello, World!");
        

        JavaScript 可以通过以下方式轻松地将其评估为“函数对象”:

        var functionObject = eval(
            '(function(a) {' +
            '    return a;' +
            '})'
        );
        
        console.log('your code is: ' + '(' + functionObject.toString() + ')');
        

        正如你所看到的,js 可以很容易地把它解析成一个对象,然后再解析成一个字符串,只是需要添加 '(' 和 ')' 以使其 eval() 不会导致错误"Uncaught SyntaxError: Unexpected token (".

        不管怎样,在PHP中也可以做类似的事情:

        <?php
        
        $functionObject = eval(
            'return function($a) {' .
            '    return $a;' .
            '};'
        );
        
        echo $functionObject("hi");
        ?>
        

        知道了这一点,你必须让 JavaScript 将 JavaScript 函数对象转换为 PHP 函数对象,或者走简单的路线,只进行翻译。

        问题在于 JavaScript(ES6) 比 PHP 更具表现力(5.6, 7 可能更好,但如果没有 service pack 1 windows 7 它就无法工作,所以我无法在这台计算机上运行它) .这反过来意味着 JavaScript 有很多功能,PHP 没有,例如:

        (function() {
            console.log("Hello World");
        })();
        

        不适用于 PHP 5.6,因为它不支持自执行函数。这意味着您需要做更多的工作才能将其翻译成:

        call_user_func(function() {
            echo "hello, world!" . "\n";
        });
        

        还有一个问题是 PHP 并没有像 javascript 那样真正使用原型,因此很难翻译它。

        无论如何,最终 php 和 javascript 非常相似,以至于您基本上可以在例外情况下使用它们。

        例如:(PHP)

        /* 据我所知,不能描述为函数,因为不是原型 */ 类控制台{ 静态函数日志($文本){ 回声$文本。 "\n"; } };

        call_user_func(function() { $myScopeVariable = "嘿,这不是 JavaScript!"; 控制台::log($myScopeVariable); });

        例如JavaScript:

        /* javascript requires brackets because semicolons are not mandatory */
        var almost_echo = (console.log.bind(console));
        

        结论

        您可以在 PHP 和 JavaScript 之间进行转换,但是将 PHP 转换为 JavaScript 比将 JavaScript 转换为 PHP 容易得多,因为 JavaScript 本身更具表现力,而 PHP 必须创建类来表示许多 JavaScript 构造(够有趣了,php 可以预处理php 来解决所有这些问题)。

        幸运的是,PHP 现在可以原生地理解 JSON,因此在 javascript 评估自身之后,javascript 可以读取结果结构(JavaScript 中的大多数东西是对象或函数),包括源代码,并将这些对象放入 JSON 编码形式。之后,您可以让 PHP 解析 JSON 以通过中性形式恢复代码)。

        例如

        php: jsEval('function(a){return a;}');
        js: [{"type":"function", "name": "foo", "args":["a"], body: "return a"}]
        php: oh, i get it, you mean 
        function foo($a) { return $a; } 
        

        本质上,可以说是通过“Common LISP”进行通信。当然,这将非常昂贵并且不是原生的,但是可以演示一个示例。理想情况下,我们将拥有一个封装各种脚本的本机模块,可以轻松地将 ruby​​ 转换为 php 到 perl 到 python 到 javascript,然后将结果编译到 c 中)。 javascript 通过能够评估自己以及打印自己的代码来帮助接近这一点。如果所有语言都可以做到这两件事,那会更容易完成,但遗憾的是 javascript 只是“几乎存在”(没有 un-eval 函数,您可以轻松发明它,但它还没有)

        至于更新 DOM。 PHP 可以像 JavaScript 一样轻松地做到这一点。问题是 javascript 和 php 都不知道 DOM 是什么,只是在浏览器中,dom 被方便地挂钩为“窗口”对象。您只需表现得好像窗口就在那里,当 php 被评估为 javascript 时,它将再次获得对 DOM 的访问权限。然而,要使用 dom,代码必须是“面向回调的”,因为它在评估之前不会获得 dom,但这还不错,您只需在评估完成之前不做任何事情,然后执行在 dom 可用后立即执行整个操作。

        代码如下所示:

        (() => {
        
            var php_code = `
        function ($window) {
            $window::document::getElementById('myDIV')->innerHTML = "Hello, World!";
        };
            `;
        
            window.addEventListener('load', () => {
                (eval(php_code(window)))();
            });
        })();
        

        虽然正确的做法是让函数评估为一个承诺(承诺是通用的......只要你用所有语言实现它们......)。在那之后,它就变成了一个处理本质上独立于语言的承诺/意图的问题(具体而言,意图是语言独立的,一旦意图被翻译,意图将需要可能提供或可能不提供的依赖项来实际执行从头到尾的顺序)。

        希望有一天我们会看到 JavaScript 可以评估 PHP 和 PHP 可以无缝地评估 JavaScript 的未来,至少可以完成混淆圈,允许我们编写客户端 php 和服务器端 javascript(我们已经成功了一半! )

        一些结束的想法

        1. php、perl、lisp 和其他 lambda 演算同义词需要它们自己的内置 JSON 变体。它基本上是 eval 和 uneval 但更简单,因为它不处理更令人兴奋的数据结构,如函数(JavaScript 可以在某种程度上使用 toString 取消评估,Perl 可以使用 Data::Dumper 和 Data::Dumper::Deparse 设置为1).

        2. 每一种 lambda 演算同义词语言(php、perl、lisp、...,其中声明 (function(a){return function(b){return a + b;}})(2)(3) 是有道理的(天真地,即使汇编也可以通过堆栈挖掘来做到这一点,所以它有点像 lambda 演算同义词语言,并且可以也有它自己的 JSON 变体)应该能够将一串有效代码编码成一个通用的抽象表示,该表示可以被任何其他 lambda 演算同义词语言编码和解码。

          1. 函数式编程原则规定,每个动作都可以分解为执行动作的请求,“提交列表”的转换,它堆叠提交而不执行它们,然后将提交映射到全局环境的实际转换(或者纯粹的,通过创建一个新环境并进行尾递归/将其放入队列中,并使未来的动作与新环境一起工作;或者不纯粹,通过改变全局状态并继续前进;两者在适当的抽象机制下是等价的)。这意味着您可以在 ajax 请求中发送一个 php 脚本,让服务器在虚拟提交对象上象征性地执行它,然后向客户端返回它需要执行的操作列表,以使其看起来像是执行了 php)。

        【讨论】:

          【解决方案5】:

          如果你在 PHP 中内置了一个 javascript 解释器(或者至少在服务器上你可以调用它来解释嵌入了 javascript 的 HTML),那将是可能的。有一些尝试(例如http://j4p5.sourceforge.net/index.php),但我会避开这些并尝试重新考虑你在做什么。根据您的具体需求,模板(例如 Smarty 之类的东西)可能能够解决您的部分问题(当然它不会解释 javascript)。

          【讨论】:

            【解决方案6】:

            如果我理解正确,您想在 PHP 中执行 JavaScript 函数... JavaScript 在浏览器(客户端)中执行,PHP 是服务器端的,所以除非您在PHP,那行不通。

            为什么服务器上的 JS 解析器完全有意义(我想不出它应该这样做的原因)或者首先是可能的,这是另一个问题...... JS 将在 DOM 上工作服务器上不存在以及调用的函数无用(想想“window.close()”会/应该在服务器上做什么!?)。

            所以为了简短的回答:不。:)

            【讨论】:

            • 是的,我在问是否存在 PHP javascript 解释。 DOM 也可以存在于服务器上,为什么不能呢?像window.close() 这样的函数不会做任何事情。
            • 我不知道 PHP JS 解释器,我仍然怀疑它的意义。如果你在服务器上执行一些东西,为什么要使用客户端语言而不是一路使用 PHP?
            • 无意间看到这条评论 - 回顾 7 年的时光很有趣。在 2002 年,我说我们需要一个 javascript 引擎服务器端(用于 DOM 和解析)。现在 - 如果您想这样做,请考虑 Node JS。
            • 这不应该有赞成票。 V8js 将从 PHP 执行 JavaScript 代码。 php.net/manual/en/book.v8js.php
            • @JamieCarl V8 需要 2010 年 7 月推出的 PHP 5.3.3,而答案是 2010 年 4 月 :) 很高兴知道它现在可以工作,但不要指望任何人跟踪和更新所有他们多年前的回答。
            【解决方案7】:

            我在构建网络爬虫时遇到了同样的问题。您可以使用无头浏览器(例如PhantomJS)来获取最终的 DOM。您基本上是告诉 PhantomJS 为您加载数据并转储您想要的数据。

            如果您使用的是 PHP,则有一个包装器 php-phantomjs 来完成这项工作。

            【讨论】:

              【解决方案8】:

              我怀疑浏览器 JavaScript 和 PHP 是否有一些好的通用服务器端运行时。对于复杂的客户端脚本,没有“最终 DOM 状态”之类的东西。想象一下,某个 DOM 更新方法是用setTimeout 安排的。你想等它吗?如果它以同样的方式重新安排其他一些更新(例如,只是为了在页面的某处显示当前时间),你要等多久?如果页面下载了一些 AJAX 数据怎么办?你想做实际的服务器请求、模拟 cookie 等吗?我认为这太复杂了,无法以一种好的方式实施。好吧,也许 Google 在他们的爬虫中有类似的东西,但它是专门为他们的特殊需求而设计的吗?

              【讨论】:

                【解决方案9】:

                有一些新的服务器在服务器端运行 Javascript 并且能够操作 DOM,但它与 PHP 无关。

                http://jaxer.org/

                【讨论】:

                  【解决方案10】:
                  function visible() {
                      echo '<script type="text/javascript">
                          var o = document.getElementById("overlay");
                          o.style.visibility = "visible"; 
                      </script>';
                  }
                  

                  这是我经常用于在 PHP 中运行 JavaScript 的好方法

                  【讨论】:

                  • 在 PHP 中不运行 javscript,它在用户的客户端浏览器上运行。
                  猜你喜欢
                  • 2011-07-10
                  • 1970-01-01
                  • 2013-05-09
                  • 2014-10-22
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多