Search code examples
javascriptphp

How to run PHP in Javascript (browser)?


This is not another of those questions, this is about parsing and interpreting PHP in the browser with JS.

How can you run PHP in JavaScript? I am not asking about running PHP in the server and then send the resulting string to the browser as JavaScript. I am literally talking about JavaScript parsing and running PHP.

This might be useful in many places:

  • An express Node.js app that has to use a PHP module.
  • A small REPL for the browser that does not need a whole VM per instance. Ideal for learning PHP.
  • Making a template engine for a static site constructor.

I've searched around and found php-parser and babel-preset-php, but nothing to run it. Ideally I'm looking for something like this, though I couldn't find anything through Google/SO/etc:

// No server needed, "just" Javascript parsing PHP
alert(php(`<?= "Hello world" ?>`));

If you know a better way than my own answer, please feel free to share it! I'm very curious about what the community thinks.


Solution

  • It is possible! Using the two libraries mentioned in the question, dissect babel-preset-php and reuse some parts to transpile PHP to Javascript, and then eval the Javascript. Here is a working demo, feel free to write some basic PHP in the <textearea> and press run to run the PHP in the browser:

    const $ = sel => document.querySelector(sel);
    $('#horrible').addEventListener('submit', e => {
      e.preventDefault();
      eval($('#horrible textarea').value);
    });
    body, html {
      margin: 0;
    }
    
    textarea {
      line-height: 1.5;
      margin: 0;
      height: 2.1em;
      padding: .3em .6em;
      border: 1px solid #ccc;
      background-color: #fff;
      border-radius: .2em;
      transition: all 0.3s;
      width: 90%;
    }
    
    button {
      display: inline-block;
      text-align: center;
      margin: 0;
      padding: .3em .9em;
      vertical-align: middle;
      background: #0074d9;
      color: #fff;
      border: 0;
      border-radius: .2em;
      width: auto;
      user-select: none;
      margin: .3em 0;
      cursor: pointer;
      transition: all 0.3s;
      border-radius: .2em;
      height: auto;
      box-shadow: 0 0 rgba(0,0,0,0) inset;
    }
    <form id="horrible">
    <textarea style="min-height:150px">const vars = { icon: &#x27;&#x1F389;&#x27; };
    const out = php(&#x60;&#x3C;?= &#x22;for fun! &#x22;.$icon ?&#x3E;&#x60;, vars);
    alert(out);</textarea>
    <button data-tooltip="Are you sure? Like, 100%? There is no coming back">EVAL()</button>
    
    <script src="https://francisco.io/blog/running-php-in-javascript/php.min.js"></script>

    Here is the actual code snippet used to build the php.js file linked above:

    import parser from 'php-parser';
    import translator from './translator';
    import generator from '@babel/generator';
    
    const run = (code, opts) => {
      // Make a closure so that `out` doesn't collide with the PHP variables:
      let out = '';
      // Define `echo` since it's used in the transpiled JS code for some reason
      opts.echo = opts.echo || (str => out += str);
      // Pretend this is safe. Pro tip: IT IS NOT SAFE
      new Function(...Object.keys(opts), code)(...Object.values(opts));
      return out;
    }
    
    export default function (src, opts = {}) {
      const ast = new parser().parseCode(src);
      const file = translator.translateProgram(ast);
      const code = generator(file).code;
      return run(code, opts);
    };