Выполнить javascript в PHP

Я генерирую вашу типичную HTML-страницу Web 2.0 с PHP: она содержит много тегов <script> и javascript-код, которые существенно изменят DOM после события загрузки.

Есть ли способ получить окончательный код HTML непосредственно с PHP, не открывая страницу с помощью какого-либо браузера?

Например, предположим, что 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 = <html>....<body><p>Hi!</p></body></html> .

Это возможно?

EDIT : поскольку многие из вас были озадачены моей просьбой, я объясню причину. К сожалению, все пользовательские образы были сделаны в javascript, и это делает сайт неприступным для поисковых систем. Поэтому я захотел отправить им HTML-код события post-ready.

Чтобы оценить код JavaScript с помощью PHP , просмотрите расширение движка V8 JavaScript , которое вы можете скомпилировать в свой двоичный файл PHP:

V8 – это реализация JavaScript с открытым исходным кодом Google .

Лучшее решение, которое я могу найти, – использовать HtmlUnit http://htmlunit.sourceforge.net/ на сервере, чтобы выполнить ваш html с помощью javascript и вернуть последний html, который пользователь увидит в браузере.

Библиотека имеет хорошую поддержку JavaScript и безгласна, поэтому вы должны иметь возможность запускать ее на сервере.

Вам нужно будет написать небольшую оболочку Java, которая может принимать входные данные через командную строку и передавать ее на HtmlUnit для обработки, а затем возвращать результат вам. Затем вы можете вызвать эту оболочку из PHP.

Если я правильно понимаю, вы хотите выполнить JavaScript-функцию в PHP … JavaScript выполняется в браузере (на стороне клиента), PHP является серверным, поэтому, если вы не пишете JavaScript-парсер в PHP, это не будет работать.

Почему JS-парсер на сервере имеет смысл вообще (я не могу придумать причину, почему это должно) или возможно в первую очередь, это другой вопрос … JS будет работать на DOM, который не существуют на сервере, а также вызываются функции, которые бесполезны (подумайте о том, что «window.close ()» будет / должно делать на сервере !?).

Поэтому, чтобы ответить коротко: Нет. 🙂

У вас есть 2 проблемы:

  1. Выполнить JavaScript.
  2. Обновите DOM (html после запуска javascript).

Для выполнения javascript вам понадобится механизм javascript. В настоящее время 3 доступны для вашего использования:

  1. V8 : Google для Chrome. Расширение PHP.
  2. Rhino : Mozilla для Firefox. Доступно только в JAVA.
  3. JavaScriptCore : Apple для Safari. Доступно только в C.

Когда у вас есть механизм javascript, вам нужно будет управлять DOM (Document Object Model). Это позволяет анализировать HTML на такие объекты, как узлы DOM, текстовые узлы, элементы и т. Д. Кроме того, вам нужно будет синхронизировать DOM с механизмом JavaScript и установить DOM-библиотеку в вашем javascript-движке. Хотя могут быть разные способы сделать это, я предпочитаю просто включать / оценивать автономный JavaScript DOM в движок и просто передавать HTML на это.

  1. Env-JS JavaScript DOM-библиотека. Совместимость с прототипом / jQuery.
  2. jsdom JavaScript DOM-библиотека для NodeJS.

Теперь, когда у вас есть как JavaScript Engine, так и DOM-библиотека, вы можете теперь оценить большинство скриптов без проблем.

Лучший ответ

NodeJS, который поставляется как автономный исполняемый файл, имеет механизм javascript, а также DOM-манипуляцию в 1. Кроме того, вы можете использовать его как веб-сервер. Возможно, это лучшее решение вашей проблемы, однако, если PHP является обязательным, придерживайтесь того, что упоминалось выше.

Было бы возможно, если бы у вас был встроенный в PHP интерпретатор javascript (или, по крайней мере, что-то на сервере, которое вы могли бы вызвать для интерпретации HTML с встроенным javascript). Произошли некоторые попытки (например, http://j4p5.sourceforge.net/index.php ), но я бы избежал их и попытался переосмыслить то, что вы делаете. В зависимости от ваших конкретных потребностей шаблон (т. Е. Что-то вроде Smarty ) может решить часть вашей проблемы (но, тем не менее, не будет интерпретировать javascript).

Этот вопрос очень похож на выполнение javascript в javascript или php в php. Ответ заключается в том, что вы можете его оценить. Если php может оценивать javascript, а javascript может eval php, у нас не было бы этого обсуждения.

Для того, чтобы JavaScript для eval PHP, он должен разобрать PHP-код в структуру, которая представляет скрипт. JavaScript может легко сделать это с помощью обозначения объекта JavaScript (не формата JSON, а фактического представления) и функционального разрушения скрипта.

Вот наивный пример JavaScript-интерпретации PHP (более честный пример не был бы таким надуманным, но проанализировал бы php в своем собственном JSON-подобном представлении или, возможно, bytecode, а затем интерпретировал бы это json-подобное представление или байт-код на javascript-эмуляции 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 может легко создать «JSONified» версию чего угодно (до тех пор, пока она не является родной), поэтому вы можете отправить 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 : Неожиданный маркер (".

Независимо от того, что можно сделать в PHP:

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

Зная это, вам нужно, чтобы JavaScript преобразовал объект функции JavaScript в объект функции PHP или прошел простой путь только для перевода.

Проблема заключается в том, что JavaScript (ES6) гораздо более выразителен, чем PHP (5.6, 7 может быть лучше, но он не работает без окна пакета обновления 1, поэтому я не могу запустить его на этом компьютере). Это, в свою очередь, означает множество функций JavaScript, у которых PHP отсутствует, например:

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

Не будет работать на PHP 5.6, потому что он не поддерживает функции самостоятельного выполнения. Это означает, что вам нужно сделать больше работы, чтобы перевести его на:

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

Есть также проблемы в том, что PHP действительно не использует прототипы, как делает javascript, поэтому очень сложно сделать перевод этого.

Во всяком случае, в конечном счете php и javascript ОЧЕНЬ похожи, настолько, что вы можете по существу использовать один в другом с исключениями.

например: (PHP)

/ * не может описать как функцию, насколько я знаю, так как не прототипная консоль * / class {static function log ($ text) {echo $ text. "\ П"; }};

call_user_func (function () {$ myScopeVariable = "Эй, это не JavaScript!"; console :: 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, по крайней мере, заполнить круг путаницы, позволяющий нам писать javascript на стороне клиента и стороне сервера (мы на полпути!)

некоторые конечные мысли

  1. php, perl, lisp и другие синонимы лямбда-исчисления нуждаются в собственном встроенном варианте JSON. Это в основном eval и uneval, но проще в том, что он не заботится о более захватывающих структурах данных, таких как функции (которые JavaScript может несколько раз использовать toString, и Perl может использовать Data :: Dumper с Data :: Dumper :: Deparse, установленным для 1).

  2. каждый из языков синонимов лямбда-исчисления (php, perl, lisp, …, где оператор (function(a){return function(b){return a + b;}})(2)(3) имеет смысл (наивно даже сборка может сделать это с помощью копания в стеке, поэтому его несколько язык синонимов лямбда-исчисления и также может иметь собственный вариант JSON) должны иметь возможность кодировать строку действительного кода в общее абстрактное представление, которое может быть закодировано и декодируется с любого языка синонимов лямбда-исчисления.

    1. принципы функционального программирования диктуют, что каждое действие может быть разбито на запрос на выполнение действия, преобразование «списка фиксации», которое стеки совершает, не делая их, а затем сопоставляет фиксации фактическим преобразованиям глобальной среды (либо чистым, путем создавая новую среду и выполняя хвостовую рекурсию / ставя ее в очередь, и будущие действия будут работать с новой средой, или неуверенно, путем изменения глобального состояния и перехода, причем эти два являются равномерными с надлежащими механизмами абстракции). Это означает, что вы можете отправить php-скрипт в ajax-запрос, чтобы сервер символически выполнил его на фиктивных объектах-компиляторах, а затем вернул клиенту список действий, которые он должен выполнить, чтобы он выглядел как выполненный php).

Я сомневаюсь, что есть несколько хороших серверных сред общего назначения для браузера JavaScript в целом и в PHP. Для сложных клиентских скриптов нет такой вещи, как «конечное состояние DOM». Представьте, что некоторый метод обновления DOM запланирован с помощью setTimeout . Вы хотите подождать? И если он перенастроит другое обновление таким же образом (например, чтобы показать текущее время где-то на странице), как долго вы будете ждать? А что, если страница загружает некоторые данные AJAX? Вы хотите выполнять фактические запросы сервера, эмулировать файлы cookie и т. Д.? Я думаю, что это слишком сложно, чтобы быть реализованы в хорошем смысле. Ну, может быть, у Google есть что-то подобное в своем гусеничном ходу, но он специализируется на своих конкретных потребностях.

Я столкнулся с такой же проблемой при создании веб-искателя. Вы можете получить окончательный DOM с помощью браузера без браузера, такого как PhantomJS . Вы в основном говорите, что PhantomJS загружает данные для вас и выгружает нужные данные.

Если вы используете PHP, для выполнения этой задачи есть оболочка php-phantomjs .

Появились новые серверы, которые запускают Javascript на стороне сервера и могут манипулировать DOM, но это не имеет ничего общего с PHP.

http://jaxer.org/

 <?php function visible() { echo '<script type="text/javascript"> var o = document.getElementById("overlay"); o.style.visibility = "visible"; </script>'; } ?> 

Это хороший способ, который я часто использовал для запуска javascript в php

 <?php function visible() { return ('<script type="text/javascript">var o = document.getElementById("cf"); document.write(o.innerHTML); </script>'); } echo visible(); ?>