在 PHP 中执行 javascript
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2699180/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Execute javascript in PHP
提问by Thomas Bonini
I'm generating your typical Web 2.0 HTML page with PHP: it contains a lot of <script>tags and javascript code that will substantially change the DOM after the load event.
我正在使用 PHP 生成典型的 Web 2.0 HTML 页面:它包含大量<script>标记和 javascript 代码,它们将在加载事件后显着更改 DOM。
Is there a way to get the final HTML code directly from PHP, without opening the page with any browser?
有没有办法直接从 PHP 获取最终的 HTML 代码,而无需使用任何浏览器打开页面?
For example, let's say the HTML for the page is (it's just an example):
例如,假设页面的 HTML 是(这只是一个示例):
<html>
<head>
<script>...the jquery library code...</script>
<script>$(document).ready(function() { $("body").append("<p>Hi!</p>");</script>
</head>
<body>
</body>
</html>
This HTML is saved in the $htmlPHP variable. Now, I want to pass that variable to some function that will return $result = <html>....<body><p>Hi!</p></body></html>.
此 HTML 保存在$htmlPHP 变量中。现在,我想将该变量传递给某个将返回 $result = 的函数<html>....<body><p>Hi!</p></body></html>。
Is this possible?
这可能吗?
EDIT: since many of you were perplexed by my request I'll explain the reason. Unfortunately everything user facing was made in javascript and this makes the website uncrawlable by search engines. So I wanted to send them the post-ready event HTML code instead.
编辑:由于你们中的许多人对我的要求感到困惑,我将解释原因。不幸的是,用户面对的一切都是用 javascript 制作的,这使得网站无法被搜索引擎抓取。所以我想向他们发送后期准备好的事件 HTML 代码。
回答by SteAp
To evaluate JavaScript code using PHP, have a look at the V8 JavaScript engine extension, which you may compile into your PHP binary:
要使用 PHP 评估 JavaScript 代码,请查看V8 JavaScript 引擎扩展,您可以将其编译为 PHP 二进制文件:
回答by Sijin
The best solution that I could find is to use HtmlUnit http://htmlunit.sourceforge.net/on the server to execute your html with the javascript and get back the final html that the user would see on the browser.
我能找到的最佳解决方案是在服务器上使用 HtmlUnit http://htmlunit.sourceforge.net/用 javascript 执行您的 html 并取回用户将在浏览器上看到的最终 html。
The library has good support for JavaScript and is headless so you should be able to run it on the server.
该库对 JavaScript 有很好的支持,并且是无头的,因此您应该能够在服务器上运行它。
You would need to write a small Java wrapper that could accept input via the command line and pass it onto HtmlUnit for processing and then return the result to you. You could then call this wrapper from PHP.
您需要编写一个小型 Java 包装器,它可以通过命令行接受输入并将其传递给 HtmlUnit 进行处理,然后将结果返回给您。然后您可以从 PHP 调用这个包装器。
回答by mAsT3RpEE
You have 2 problems:
你有两个问题:
- Execute JavaScript.
- Update DOM (the html after executing javascript).
- 执行 JavaScript。
- 更新 DOM(执行 javascript 后的 html)。
To execute javascript you will need a javascript engine. There are currently 3 available for your use:
要执行 javascript,您需要一个 javascript 引擎。目前有 3 种可供您使用:
- V8: By Google for Chrome. PHP extension.
- Rhino: By Mozilla for Firefox. Only available in JAVA.
- JavaScriptCore: By Apple for Safari. Only available in C.
- V8:由 Google 用于 Chrome。PHP扩展。
- Rhino:由 Mozilla 用于 Firefox。仅在 JAVA 中可用。
- JavaScriptCore:由 Apple 用于 Safari。仅在 C 中可用。
Once you have a javascript engine you will need to manage DOM (Document Object Model). This allows you to parse HTML into objects like DOM Nodes, Text Nodes, Elements, etc. On top of that you will need to sync your DOM with javascript engine and install DOM library in your javascript engine. Though there may be various ways to do this i prefer to simply include / evaluate a standalone JavaScript DOM into the engine and simply pass HTML to that.
一旦你有了一个 javascript 引擎,你就需要管理 DOM(文档对象模型)。这允许您将 HTML 解析为 DOM 节点、文本节点、元素等对象。最重要的是,您需要将 DOM 与 javascript 引擎同步并在 javascript 引擎中安装 DOM 库。尽管可能有多种方法可以做到这一点,但我更喜欢简单地将独立的 JavaScript DOM 包含/评估到引擎中,然后简单地将 HTML 传递给它。
- Env-JSJavaScript DOM library. Compatible with prototype / jQuery.
- jsdomJavaScript DOM library for NodeJS.
Now that you have both a JavaScript Engine and DOM library, you can now evaluate most scripts without issue.
现在您拥有 JavaScript 引擎和 DOM 库,您现在可以毫无问题地评估大多数脚本。
Best Answer
最佳答案
NodeJS, which comes as a standalone executable, has a javascript engine as well as DOM manipulation all in 1. On top of that you can also use it as a web server. Perhaps this is a better solution to your problem however if PHP is a must, stick to what is mentioned above.
NodeJS 是一个独立的可执行文件,具有 javascript 引擎和 DOM 操作合二为一。除此之外,您还可以将其用作 Web 服务器。也许这是您问题的更好解决方案,但是如果必须使用 PHP,请坚持上面提到的内容。
回答by Dmitry
This question is very similar to how to execute javascript in javascript, or php in php, The answer is that you can eval it. If php could eval javascript and javascript could eval php, we would not have this discussion.
这个问题和how to execute javascript in javascript, or php in php 非常相似,答案是你可以eval它。如果 php 可以 eval javascript 并且 javascript 可以 eval php,我们就不会有这个讨论。
In order for JavaScript to eval PHP, it has to parse the PHP code into a structure that represents the script. JavaScript can easily do this with JavaScript object notation(not JSON format but the actual representation), and functionally breaking down the script.
为了让 JavaScript 评估 PHP,它必须将 PHP 代码解析为表示脚本的结构。JavaScript 可以使用 JavaScript 对象表示法(不是 JSON 格式,而是实际表示)轻松地做到这一点,并在功能上分解脚本。
Here's a naive example of JavaScript interpreting PHP(a more honest example would not be so contrived, but parse the php into its own JSON-like representation or possibly bytecode, then interpret this json-like representation or bytecode on a javascript emulation of the php virtual machine, but nonetheless):
这是 JavaScript 解释 PHP 的一个天真的例子(一个更诚实的例子不会那么做作,而是将 php 解析成它自己的类似 JSON 的表示或可能的字节码,然后在 php 的 javascript 模拟上解释这个类似 json 的表示或字节码虚拟机,但仍然如此):
(() => {
'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(''))"));
console.log('converted to "' + code + '"');
eval(code);
}
};
partialPHPEval(phpSnippet);
})();
The problem is that PHP is not javascript, and suffers from the fact that it's eval is much weaker than javascript's.
问题是 PHP 不是 javascript,而且它的 eval 比 javascript 弱得多。
This creates a problem where php can make a request to tokenize javascript to PHP easily: JavaScript can easily create a "JSONified" version of anything(as long as it is not native), so you could have PHP send a request to a nodejs server with the script you want to evaluate.
这会产生一个问题,即 php 可以轻松地发出将 javascript 标记为 PHP 的请求:JavaScript 可以轻松创建任何内容的“JSONified”版本(只要它不是本机的),因此您可以让 PHP 向 nodejs 服务器发送请求使用您要评估的脚本。
for instance:(PHP code)
例如:(PHP代码)
include "some_file_defining_jsEval.php";
$wantedObject = function($a) {
return $a;
};
$resultingObject = jsEval(
'(function(a) {' .
' return a;' .
'})'
);
echo $resultingObject("Hello, World!");
JavaScript can easily eval it to a "function object" by doing:
JavaScript 可以通过执行以下操作轻松将其评估为“函数对象”:
var functionObject = eval(
'(function(a) {' +
' return a;' +
'})'
);
console.log('your code is: ' + '(' + functionObject.toString() + ')');
as you can see, js can easily parse it into an object, and back into a string, with a minor nuisance that '(' and ')' must be added in order to make it eval() without causing an error "Uncaught SyntaxError: Unexpected token (".
如您所见,js 可以轻松地将其解析为一个对象,然后再解析为一个字符串,但有一点麻烦,即必须添加 '(' 和 ')' 以使其 eval() 不会导致错误“Uncaught SyntaxError : 意外的标记 (”。
Regardless, a similar thing can be done in PHP:
无论如何,类似的事情可以在 PHP 中完成:
<?php
$functionObject = eval(
'return function($a) {' .
' return $a;' .
'};'
);
echo $functionObject("hi");
?>
Knowing this, you have to have JavaScript convert the JavaScript function object into a PHP function object, or go the easy route of just translating.
知道了这一点,您必须让 JavaScript 将 JavaScript 函数对象转换为 PHP 函数对象,或者走简单的翻译路线。
The problem lies in the fact that JavaScript(ES6) is much more expressive than PHP(5.6, 7 might be better but it doesn't work without service pack 1 windows 7 so I can't run it on this computer). This in turn means a lot of features JavaScript has, PHP does not have, for example:
问题在于 JavaScript(ES6)比 PHP 更具表现力(5.6、7 可能更好,但如果没有 service pack 1 windows 7,它就无法运行,所以我无法在这台计算机上运行它)。这反过来意味着 JavaScript 有很多功能,PHP 没有,例如:
(function() {
console.log("Hello World");
})();
Won't work on PHP 5.6 because it does not support self executing functions. This means you need to do more work to translate it into:
不适用于 PHP 5.6,因为它不支持自执行函数。这意味着您需要做更多的工作才能将其转换为:
call_user_func(function() {
echo "hello, world!" . "\n";
});
There are also issues in that PHP doesn't really use prototypes the way javascript does, so it's very hard to do translation of that.
还有一些问题是,PHP 并没有像 javascript 那样真正使用原型,因此很难对其进行翻译。
Anyway, ultimately php and javascript are VERY similar, so much so that you can essentially use one in another with exceptions.
无论如何,最终 php 和 javascript 非常相似,以至于您基本上可以在另一个中使用一个例外。
e.g: (PHP)
例如:(PHP)
/* can't describe as a function as far as I know, since not prototypical */ class console { static function log($text) { echo $text . "\n"; } };
/* 就我所知,不能描述为函数,因为不是原型 */ class console { static function log($text) { echo $text . "\n"; } };
call_user_func(function() { $myScopeVariable = "Hey, this isn't JavaScript!"; console::log($myScopeVariable); });
call_user_func(function() { $myScopeVariable = "嘿,这不是 JavaScript!"; console::log($myScopeVariable); });
e.g. JavaScript:
例如 JavaScript:
/* javascript requires brackets because semicolons are not mandatory */
var almost_echo = (console.log.bind(console));
Conclusion
结论
You can translate between PHP and JavaScript, but it is much easier to translate PHP to JavaScript than JavaScript to PHP because JavaScript is more expressive natively, whereas PHP has to create classes to represent many JavaScript constructs(funny enough, php can preprocess php to fix all of these problems).
您可以在 PHP 和 JavaScript 之间进行转换,但将 PHP 转换为 JavaScript 比将 JavaScript 转换为 PHP 容易得多,因为 JavaScript 本身更具表现力,而 PHP 必须创建类来表示许多 JavaScript 结构(有趣的是,php 可以预处理 php 以修复所有这些问题)。
Fortunately, PHP can now make sense of JSON natively, so after javascript evaluates itself, javascript can read the resulting structure(most things in JavaScript are objects or functions), including the source code, and put those objects into JSON-encoded form. After that, You can make PHP parse the JSON to recover the code via a neutral form).
幸运的是,PHP 现在可以原生理解 JSON,因此在 javascript 评估自身之后,javascript 可以读取结果结构(JavaScript 中的大多数内容是对象或函数),包括源代码,并将这些对象放入 JSON 编码形式。之后,您可以让 PHP 解析 JSON 以通过中性形式恢复代码)。
e.g.
例如
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; }
Essentially, communicating via a "Common LISP" so to speak. Of course this is going to be very expensive and not native, but it's fine to demonstrate an example. Ideally we would have a native module encapsulating scripting of all kind that could easily translate ruby to php to perl to python to javascript and then compile the result to c for the heck of it). javascript helps coming close to this by being able to eval itself AS WELL as print its own code. If all languages could do both of these things, it would be much easier to accomplish, but sadly javascript is only "almost there"(there is no un-eval function, you can easily invent it but it's not there yet)
本质上,可以说是通过“通用 LISP”进行通信。当然,这将是非常昂贵的并且不是原生的,但是演示一个示例很好。理想情况下,我们将拥有一个封装各种脚本的本机模块,它可以轻松地将 ruby 转换为 php,将 perl 转换为 python 到 javascript,然后将结果编译为 c 以实现它)。javascript 通过能够评估自己以及打印自己的代码来帮助接近这一点。如果所有语言都可以做这两件事,那么实现起来会容易得多,但遗憾的是 javascript 只是“几乎在那里”(没有 un-eval 函数,您可以轻松发明它,但还没有)
As for updating DOM. PHP can do it as easily as JavaScript can. The problem is that both javascript and php have no idea what DOM is, it's just that in the browser, the dom is conveniently hooked as "window" object. You simply act as though the window is there and as the php gets evaluated to javascript, it will gain access to the DOM again. To make use of dom however, the code has to be "callback oriented" since it won't get dom until it is evaluated, but it's not bad, you just don't do anything until the evaluation is complete, and then perform the whole action at once after dom is available.
至于更新DOM。PHP 可以像 JavaScript 一样轻松地做到这一点。问题是 javascript 和 php 都不知道 DOM 是什么,只是在浏览器中,dom 很方便地被挂钩为“窗口”对象。你只是表现得好像窗口在那里一样,当 php 被评估为 javascript 时,它将再次获得对 DOM 的访问权限。然而,要使用 dom,代码必须是“面向回调的”,因为它在被评估之前不会得到 dom,但这还不错,你只是在评估完成之前什么都不做,然后执行dom 可用后立即执行整个操作。
The code would look something like:
代码如下所示:
(() => {
var php_code = `
function ($window) {
$window::document::getElementById('myDIV')->innerHTML = "Hello, World!";
};
`;
window.addEventListener('load', () => {
(eval(php_code(window)))();
});
})();
Although the proper way to do is is have the function evaluate to a promise(promises are universal... as soon as you implement them in all languages...). After that it just becomes a question of juggling promises/intents that are essentially language independent(To be specific, the intent is language independent, once the intent is translated, the intent will require dependencies that may or may not be provided to actually perform the sequence from start to finish).
虽然正确的方法是让函数评估为一个承诺(承诺是通用的......只要你在所有语言中实现它们......)。之后,它就变成了处理本质上独立于语言的承诺/意图的问题(具体来说,意图是语言独立的,一旦意图被翻译,意图将需要依赖关系,这些依赖关系可能会或可能不会被提供来实际执行从头到尾的顺序)。
Hopefully someday we will see a future where JavaScript can evaluate PHP and PHP can evaluate JavaScript seamlessly, at the very least to complete the confusion circle allowing us to write client side php and server side javascript(we're half way there!)
希望有一天我们会看到 JavaScript 可以评估 PHP 和 PHP 可以无缝评估 JavaScript 的未来,至少可以完成混淆圈,允许我们编写客户端 php 和服务器端 javascript(我们已经完成了一半!)
some ending thoughts
一些结束的想法
php, perl, lisp, and other lambda calculus synonyms need their own built in variant of JSON. It's basically eval and uneval but simpler in that it doesn't take care of the more exciting data structures like functions(which JavaScript can uneval using toString somewhat, and Perl can using Data::Dumper with Data::Dumper::Deparse set to 1).
every lambda calculus synonym language(php, perl, lisp, ..., where the statement
(function(a){return function(b){return a + b;}})(2)(3)makes sense(naively even assembly can do this with stack digging, so its somewhat of a lambda calculus synonym language, and can also have its own variant of JSON) should be able to both encode a string of valid code into a common abstract representation that can be encoded to and decoded from any other lambda calculus synonym language.- functional programming principles dictate that every action can be broken down into a request to do the action, a transformaton of a "commit list" which stacks commits without doing them, then mapping the commits to actual transformations of the global environment(either pure, by creating a new environment and doing tail recursion/putting it on the queue and have the future actions work with the new environment; or unpure, by mutating the global state and moving on; the two being equivelent with proper abstraction mechanisms). This means that you can send a php script in an ajax request, have the server symbolically execute it on dummy commit objects, then return to the client a list of actions it needs to do to make it seem like it executed php).
php、perl、lisp 和其他 lambda 演算同义词需要它们自己的内置 JSON 变体。它基本上是 eval 和 uneval,但更简单,因为它没有处理更令人兴奋的数据结构,如函数(JavaScript 可以使用 toString 对它进行 uneval,而 Perl 可以使用 Data::Dumper 并将 Data::Dumper::Deparse 设置为1)。
每个 lambda 演算同义词语言(php,perl,lisp,...,其中语句
(function(a){return function(b){return a + b;}})(2)(3)有意义(天真地甚至汇编可以通过堆栈挖掘来做到这一点,所以它有点像 lambda 演算同义词语言,并且也可以有自己的变体JSON) 应该能够将一串有效代码编码为一个通用的抽象表示,该表示可以被编码为任何其他 lambda 演算同义词语言,也可以从任何其他 lambda 演算同义词语言中解码。- 函数式编程原则规定,每个动作都可以分解为执行动作的请求,一个“提交列表”的转换,它堆叠提交而不执行它们,然后将提交映射到全局环境的实际转换(无论是纯的,通过创建一个新环境并进行尾递归/将其放在队列中并使未来的操作与新环境一起工作;或者不纯,通过改变全局状态并继续前进;两者与适当的抽象机制等效)。这意味着您可以在 ajax 请求中发送一个 php 脚本,让服务器在虚拟提交对象上象征性地执行它,然后将它需要执行的操作列表返回给客户端,使其看起来像是执行了 php)。
回答by wimvds
It would be possible if you had a javascript interpreter built into PHP (or at least something on the server you could call to interpret the HTML with javascript embedded). There have been some attempts (eg http://j4p5.sourceforge.net/index.php), but I would steer clear of these and try to rethink what you're doing. Depending on your specific needs, templating (ie. something like Smarty) might be able to solve part your problem (it will however NOT interpret javascript of course).
如果您在 PHP 中内置了一个 javascript 解释器(或者至少在服务器上您可以调用它来解释嵌入了 javascript 的 HTML),那将是可能的。已经有一些尝试(例如http://j4p5.sourceforge.net/index.php),但我会避开这些并尝试重新思考你在做什么。根据您的特定需求,模板(即Smarty 之类的东西)可能能够解决您的部分问题(当然它不会解释 javascript)。
回答by Select0r
If I understand you right, you'd like to execute a JavaScript-function in PHP ... JavaScript is executed in the browser (client side), PHP is server-sided, so unless you write a JavaScript-parser in PHP, that won't work.
如果我理解正确,您想在 PHP 中执行 JavaScript 函数...... JavaScript 在浏览器(客户端)中执行,PHP 是服务器端,所以除非您在 PHP 中编写 JavaScript 解析器,否则不会工作。
Why a JS-parser on the server would make sense at all (I can't think of a reason why it should) or is possible in the first place, is another question ... JS will work on a DOM that doesn't exist on the server as well as functions are called that are useless (think of what "window.close()" would/should do on the server!?).
为什么服务器上的 JS 解析器完全有意义(我想不出它应该的原因)或者首先是可能的,这是另一个问题...... JS 将在没有的 DOM 上工作存在于服务器上以及调用无用的函数(想想“window.close()”会/应该在服务器上做什么!?)。
So to make the answer short: No. :)
所以要简短回答:不。:)
回答by Hyder B.
I faced the same issue while building a web crawler. You can get the final DOM by using a headless browser such as PhantomJS. You basically tell PhantomJS to load the data for you and dump the data you want.
我在构建网络爬虫时遇到了同样的问题。您可以使用无头浏览器(例如PhantomJS )获取最终的 DOM 。您基本上是告诉 PhantomJS 为您加载数据并转储您想要的数据。
If you are using PHP, there is a wrapper, php-phantomjsto do the job.
如果您使用的是 PHP,则有一个包装器php-phantomjs来完成这项工作。
回答by SergGr
I doubt that there are some good general purpose server-side runtimes for browser JavaScript generally and in PHP specifically. For complicated client scripts there is no such thing as "final DOM state". Imagine that some DOM-updating method is scheduled with setTimeout. Do you want to wait for it? And if it reschedules some other update in the same way (for example just to show current time somewhere on the page), how long are you going to wait? And what if page does some AJAX data downloading? Do you want to do actual server requests, emulate cookies, etc.? I think this is all too complicated to be implemented in a good way. Well, maybe Google has something like this in their crawler, but is it specialized for their particular needs.
我怀疑是否有一些很好的通用服务器端运行时用于浏览器 JavaScript,特别是在 PHP 中。对于复杂的客户端脚本,没有“最终 DOM 状态”这样的东西。想象一下,某个 DOM 更新方法是用setTimeout. 你要等吗?如果它以相同的方式重新安排其他一些更新(例如只是为了在页面的某处显示当前时间),你要等多久?如果页面会下载一些 AJAX 数据怎么办?您想执行实际的服务器请求、模拟 cookie 等吗?我认为这太复杂了,无法以好的方式实施。好吧,也许谷歌在他们的爬虫中有这样的东西,但它是否专门满足他们的特定需求。
回答by jef2904
There are new servers that run Javascript server-side and are able to manipulate the DOM but it has nothing to do with PHP .
有一些新的服务器运行 Javascript 服务器端并且能够操作 DOM 但它与 PHP 无关。
回答by silvius
function visible() {
echo '<script type="text/javascript">
var o = document.getElementById("overlay");
o.style.visibility = "visible";
</script>';
}
This is a good way i used often for running JavaScript in PHP
这是我经常用来在 PHP 中运行 JavaScript 的好方法

