Running locally a PHP program from the browser with Node.js

Node.js is the link that connects the browser to executable files on a local machine.

The diagram below shows how the system works:

  1. We start node with the server script :
    node runphp.js
  2. We type the script's locale URL in the browser :
    localhost:1000/dirlist.php
  3. Node launches the execution of the script with the runner.exec command.
  4. The script displays a result with the echo command.
  5. The result is send to a new HTML page by Node.

PHP, HTML and Node.js

To start the program, you type the program name in the URL bar:

localhost:1000/dirlist.php

And you can also pass variables to the program, in this form:

localhost:1000/dirlist.php?x=test 

The JavaScript code is derived from the server code that was already used to create a HTML file server with Node.js. But this time, instead of displaying the content, we use the module child_process to run the program, and it is then the program output that will be displayed.
It works on a local machine, or on a remote host.

1) As always we first create a server

var server = http.createServer(php);
server.listen(1000);
console.log("PHP ready to run script given on port 1000.");

And we assign a communication port.

2) The existence of the script in the file system is checked

function php(request, response)
{
  var urlpath = url.parse(request.url).pathname;
  var param = url.parse(request.url).query;
  var localpath = path.join(process.cwd(), urlpath);
  fs.exists(localpath, function(result) { runScript(result, localpath, param, response)});
}

The file name is extracted from the URL with the parse method of the url module.
And also is extracted the parameter string with the query method. It is transmitted as is to the PHP script.

3) We run the script

function runScript(exists, file, param, response)
{
  if(!exists) return sendError(404, 'File not found', response);
  runner.exec("php " + file + " " + param,
   function(err, stdout, stderr) { sendData(err, stdout, stderr, response); });
}

The exec method of child_process has for first parameter all that is typed in the command line, so the name of the PHP interpreter, the script name and parameter list.

4) Everything displayed by the script will be displayed in the browser

function sendData(err, stdout, stderr, response)
{
  if (err) return sendError(500, stderr, response);
  response.writeHead(200,{"Content-Type": "text/plain;charset=utf-8"});
  response.write(stdout);
  response.end();
}

It is the role of the sendData function called in callback by the exec method.

5) Example of PHP script

This PHP demo script reads files in the directory and lists them. Everything it displays appears in the browser.

<?php
echo "Parameter:".$argv[1]."\n";
echo "Directory content...\n\n";

$output="";
if ($hnd = opendir('.'))
{
  while($file = readdir($hnd))
  {
    if ($file == "." || $file == "..") continue;
    $output .= "$file\n";
  }
  closedir($hnd);
}
echo $output;
?>

The parameters are found in the $argv array. The first parameter (the only one in this example) in $argv[1]. It is the task of the programmer to split the string and use its contents.

6) The full JavaScript code source

var http = require("http"),
fs = require("fs"),
path = require("path"),
url = require("url"),
runner = require("child_process");

function sendError(errCode, errString, response)
{
  response.writeHead(errCode, {"Content-Type": "text/plain;charset=utf-8"});
  response.write(errString + "\n");
  response.end();
  return false;
}

function sendData(err, stdout, stderr, response)
{
  if (err) return sendError(500, stderr, response);
  response.writeHead(200,{"Content-Type": "text/plain;charset=utf-8"});
  response.write(stdout);
  response.end();
}

function runScript(exists, file, param, response)
{
  if(!exists) return sendError(404, 'File not found', response);
  runner.exec("php " + file + " " + param,
   function(err, stdout, stderr) { sendData(err, stdout, stderr, response); });
}

function php(request, response)
{
  var urlpath = url.parse(request.url).pathname;
  var param = url.parse(request.url).query;
  var localpath = path.join(process.cwd(), urlpath);
  fs.exists(localpath, function(result) { runScript(result, localpath, param, response)});
}

var server = http.createServer(php);
server.listen(1000);
console.log("PHP ready to run script given on port 1000.");

Local server

In fact we have with this program the basis for a rudimentary local application server: by changing the script name in the URL bar, you throw different tools.
To automate the running you can put each in bookmark, and even possibly use bookmarklets to pass parameters.
This local server can also be started itself by placing the above command in a batch file that will run at session startup.