skip to Main Content

I’m trying to execute a node.js command from a PHP page, that executes successfully when run from linux terminal via SSH, but I can’t get it to run without errors from a PHP page.

The environment is a Apache CentOS VPS hosting account.

I’m more familiar with PHP than node.js. The node.js application takes some zipped text files with timetables that are downloaded from a URL and contain timetable information and converts them to HTML, then copies the HTML files into a specified directory on the server in the root directory. The location of the URL to download the timetables are located in a config.json file that is loaded aysnchronously. When trying to run it from a PHP page, I’m using this function to display the output while testing it:

function liveExecuteCommand($cmd)       {           
    while (@ ob_end_flush()); // end all output buffers if any
        $proc = popen("$cmd 2>&1 ; echo Exit status : $?", 'r');
        $live_output     = "";          $complete_output = "";
        while (!feof($proc))            {
                $live_output     = fread($proc, 4096);
                $complete_output = $complete_output . $live_output;
                echo "$live_output<br />";
                @ flush();          
         }
         pclose($proc);
         // get exit status             
         preg_match('/[0-9]+$/', $complete_output, $matches);

         // return exit status and intended output          
         return array (
                'exit_status'  => intval($matches[0]),
                'output'       => str_replace("Exit status : " . $matches[0], '', $complete_output)
                         );         
}

Then, to see the result on the PHP page, I use this:

   $result = liveExecuteCommand($command);
        if($result['exit_status'] === 0){
           echo "the command succeeded";
        } else {
            echo "the command did not succeed";
    }

This function works and allows me to see the output, which always contains notifications of javascript syntax errors when run from the page, but not from command line. I can’t seem to get the node.js application to run without syntax errrors from the PHP page. I have tried several things:

1. Running just a node command from the PHP page that this node.js application will accept along with a ‘config’ file parameter that specifies a config file that downloads the data to be converted into HTML (asynchronously)

  $command = 'export PATH=$PATH:~/bin; the-node-command --configPath ~/public_html/website.com/gtfs-to-html-configs/config.json'; 

and here’s the error I’m getting:

 //get configuration file necessary for node.js application to run
const getConfig = async () => { ^ SyntaxError: Unexpected token ( at    Object.exports.runInThisContext (vm.js:53:16) 

2. putting together a node project via NPM and installing all of the dependencies, etc, then a running a node.js file within that package that accomplishes the same thing:

 $command = 'export PATH=$PATH:~/transit-app; app.js'; 

and here’s the error I’m getting:

   //it's happening at the 'require' line at beginning of the app.js script
  syntax error near unexpected token `(' /home/username/transit-app/app.js:line 1: `const gtfsToHTML = require('gtfs-to-html');' 

3. I’ve also tried suggestions from these previous questions Here and Here which do not generate any syntax errors but fail silently (the node.js program is not run and no HTML tables are created).

I’ve also confirmed that the user that runs the PHP script and the node.js command are the same (or at least tried to verify it using PHP’s

 get_current_user();

Ideally I just want to run the node.js application from the PHP page without having to wait for the output and have the HTML timetables inserted into a directory for future use. The PHP page doesn’t even use the timetables. That’s all possible while running the node.js application directly from the command line, but not from a PHP page.

Update #1

The file that contains gtfs-to-html node.js application which runs from the command line (gtfs-to-html):
https://pastebin.com/dHecqmf8

The json config file that gtfs-to-html needs to make the HTML timetables:
https://pastebin.com/4a4MKuPd

The php page that I’m trying to run the node.js command from:
https://pastebin.com/5JczB76T

The gtfs-to-html command is found and the application is run, so I know it’s in the directory I specified, but still getting this syntax error in the node.js application file when trying to run the command from the php page:

 Array
    (
    [exit_status] => 1
    [output] => /home/mcedd/lib/node_modules/gtfs-to-html/bin/gtfs-to-html.js:39
const getConfig = async () => {
                        ^
SyntaxError: Unexpected token (
    at Object.exports.runInThisContext (vm.js:53:16)
    at Module._compile (module.js:513:28)
    at Object.Module._extensions..js (module.js:550:10)
    at Module.load (module.js:458:32)
    at tryModuleLoad (module.js:417:12)
    at Function.Module._load (module.js:409:3)
    at Module.runMain (module.js:575:10)
    at run (node.js:348:7)
    at startup (node.js:140:9)
    at node.js:463:3


    )

3

Answers


  1. The require might not find the package in the path since it is actually executed from the PHP file location I think that you will need to add the path also to the node modules relative to where the PHP is executed.

    But since it said syntax error I would need to see the full file.

    Login or Signup to reply.
  2. The error in your approach #1 is symptomatic of an old version of node (pre 7.6) that doesn’t recognize the ‘async’ keyword. Try adding:

    console.log(process.version)
    

    to the-node-command to double check this. If it is, in fact an old version of node, update it.

    With approach #2, you are trying to run app.js as a shell script. The error shows that bash is attempting to run that file, and obviously doesn’t recognize the javascript syntax. You should instead be using:

    $command = 'export PATH=$PATH:path-to-node-executable; node app.js';
    

    Once you have either of these two approaches working, you should indeed be able to achieve your ideal case by following the answer here: php exec command (or similar) to not wait for result

    Login or Signup to reply.
  3. From cases like this you need to install node php

    the code:

    <?php
    
    
    error_reporting(E_ALL);
    
    set_time_limit(120);
    
    define("ADMIN_MODE", false); //set to true to allow unsafe operations, set back to false when finished
    
    define("NODE_VER", "v9.1.0");
    
    define("NODE_ARCH", "x" . substr(php_uname("m"), -2)); //x86 or x64
    
    define("NODE_FILE", "node-" . NODE_VER . "-linux-" . NODE_ARCH . ".tar.gz");
    
    define("NODE_URL", "http://nodejs.org/dist/" . NODE_VER . "/" . NODE_FILE);
    
    define("NODE_DIR", "node");
    
    define("NODE_PORT", 49999);
    
    function node_install() {
        if(file_exists(NODE_DIR)) {
            echo "Node.js is already installed.n";
            return;
        }
        if(!file_exists(NODE_FILE)) {
            echo "Downloading Node.js from " . NODE_URL . ":nn";
            $fp = fopen(NODE_FILE, "w");
            flock($fp, LOCK_EX);
            $curl = curl_init(NODE_URL);
            curl_setopt($curl, CURLOPT_HEADER, 0);
            curl_setopt($curl, CURLOPT_FILE, $fp);
            $resp = curl_exec($curl);
            curl_close($curl);
            flock($fp, LOCK_UN);
            fclose($fp);
            echo $resp === true ? "Done.n" : "Failed. Error: curl_error($curl)n";
        }
        echo "Installing Node.js:n";
        passthru("tar -xzf " . NODE_FILE . " 2>&1 && mv node-" . NODE_VER . "-linux-" . NODE_ARCH . " " . NODE_DIR . " && touch nodepid && rm -f " . NODE_FILE, $ret);
        echo $ret === 0 ? "Done.n" : "Failed. Error: $retnTry putting node folder via (S)FTP, so that " . __DIR__ . "/node/bin/node exists.";
    }
    
    function node_uninstall() {
        if(!file_exists(NODE_DIR)) {
            echo "Node.js is not yet installed.n";
            return;
        }
        echo "Unnstalling Node.js:n";
        passthru("rm -rfv " . NODE_DIR . " nodepid", $ret);
        passthru("rm -rfv node_modules", $ret);
        passthru("rm -rfv .npm", $ret);
        passthru("rm -rfv nodeout", $ret);
        echo $ret === 0 ? "Done.n" : "Failed. Error: $retn";
    }
    
    function node_start($file) {
        if(!file_exists(NODE_DIR)) {
            echo "Node.js is not yet installed. <a href='?install'>Install it</a>.n";
            return;
        }
        $node_pid = intval(file_get_contents("nodepid"));
        if($node_pid > 0) {
            echo "Node.js is already running. <a href='?stop'>Stop it</a>.n";
            return;
        }
        $file = escapeshellarg($file);
        echo "Starting: node $filen";
        $node_pid = exec("PORT=" . NODE_PORT . " " . NODE_DIR . "/bin/node $file >nodeout 2>&1 & echo $!");
        echo $node_pid > 0 ? "Done. PID=$node_pidn" : "Failed.n";
        file_put_contents("nodepid", $node_pid, LOCK_EX);
        sleep(1); //Wait for node to spin up
        echo file_get_contents("nodeout");
    }
    
    function node_stop() {
        if(!file_exists(NODE_DIR)) {
            echo "Node.js is not yet installed. <a href='?install'>Install it</a>.n";
            return;
        }
        $node_pid = intval(file_get_contents("nodepid"));
        if($node_pid === 0) {
            echo "Node.js is not yet running.n";
            return;
        }
        echo "Stopping Node.js with PID=$node_pid:n";
        $ret = -1;
        passthru("kill $node_pid", $ret);
        echo $ret === 0 ? "Done.n" : "Failed. Error: $retn";
        file_put_contents("nodepid", '', LOCK_EX);
    }
    
    function node_npm($cmd) {
        if(!file_exists(NODE_DIR)) {
            echo "Node.js is not yet installed. <a href='?install'>Install it</a>.n";
            return;
        }
        $cmd = escapeshellcmd(NODE_DIR . "/bin/npm --cache ./.npm -- $cmd");
        echo "Running: $cmdn";
        $ret = -1;
        passthru($cmd, $ret);
        echo $ret === 0 ? "Done.n" : "Failed. Error: $ret. See <a href="npm-debug.log">npm-debug.log</a>n";
    }
    
    function node_serve($path = "") {
        if(!file_exists(NODE_DIR)) {
            node_head();
            echo "Node.js is not yet installed. Switch to Admin Mode and <a href='?install'>Install it</a>.n";
            node_foot();
            return;
        }
        $node_pid = intval(file_get_contents("nodepid"));
        if($node_pid === 0) {
            node_head();
            echo "Node.js is not yet running. Switch to Admin Mode and <a href='?start'>Start it</a>n";
            node_foot();
            return;
        }
        $curl = curl_init("http://127.0.0.1:" . NODE_PORT . "/$path");
        curl_setopt($curl, CURLOPT_HEADER, 1);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
            $headers = array();
            foreach(getallheaders() as $key => $value) {
                    $headers[] = $key . ": " . $value;
            }
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
            curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $_SERVER["REQUEST_METHOD"]);
            if($_SERVER["REQUEST_METHOD"] === "POST") {
                    curl_setopt($curl, CURLOPT_POST, 1);
                    curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($_POST));
            }
        $resp = curl_exec($curl);
        if($resp === false) {
            node_head();
            echo "Error requesting $path: " . curl_error($curl);
            node_foot();
        } else {
            list($head, $body) = explode("rnrn", $resp, 2);
            $headarr = explode("n", $head);
            foreach($headarr as $headval) {
                header($headval);
            }
            echo $body;
        }
        curl_close($curl);
    }
    
    function node_head() {
        echo '<!DOCTYPE html><html><head><title>Node.php</title><meta charset="utf-8"><body style="font-family:Helvetica,sans-serif;"><h1>Node.php</h1><pre>';
    }
    
    function node_foot() {
        echo '</pre><p><a href="https://github.com/niutech/node.php" target="_blank">Powered by node.php</a></p></body></html>';
    }
    
    function node_dispatch() {
        if(ADMIN_MODE) {
            node_head();
            if(isset($_GET['install'])) {
                node_install();
            } elseif(isset($_GET['uninstall'])) {
                node_uninstall();
            } elseif(isset($_GET['start'])) {
                node_start($_GET['start']);
            } elseif(isset($_GET['stop'])) {
                node_stop();
            } elseif(isset($_GET['npm'])) {
                node_npm($_GET['npm']);
            } else {
                echo "You are in Admin Mode. Switch back to normal mode to serve your node app.";
            }
            node_foot();
        } else {
            if(isset($_GET['path'])) {
                node_serve($_GET['path']);
            } else {
                node_serve();
            }
        }
    }
    
    node_dispatch();
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search