3

I'm forced to use a legacy PHP module (wrapper for an external API that has NO documentation at all) in my node application.

I'm trying to pass a small chunk of data to my PHP script via command line arguments like:

var spawn = require('child_process').spawn;
//...
//later on:
var LegacyScript = spawn('php', ['bridge.php', JSON.stringify(someData)]);

In my bridge.php I am doing the following:

<?php
$data = json_decode($argv[1], TRUE);
# this logs the data just fine - i can use the string and lint it / parse it - everything perfect
file_put_contents('phpgot.txt', $argv[1]);
# this is empty
file_put_contents('phpprocessed.txt', $data);
# this is NULL
file_put_contents('phpreencoded.txt', json_encode($data));
# my node module gets plain null
echo json_encode($data);
?>

Is the approach I am taking valid at all? I am a little puzzled as the data seems to arrive just fine inside my PHP bridge, but it will fail at parsing it although it is perfectly valid JSON that passes jsonlint and the likes.

Is there another (more elegant) way of passing data to the spawned process?

EDIT : So I just noticed this is only failing when there are special characters (ü,ö,ä and the like) present in the JSON string. When the content is plain latin charset it works just as expected. I'm in a all UTF-8 environment though.

m90
  • 11,434
  • 13
  • 62
  • 112
  • 2
    Does the answer here (to `utf8_encode` the input) help? http://stackoverflow.com/questions/9725248/json-encode-encodes-strings-with-unicode-copyright-character-as-null – Chris Hayes Dec 29 '13 at 19:57
  • Yeah, I just did that a second ago and it fixed my problem. I don't really get why, but then again it's PHP. Thanks a lot! – m90 Dec 29 '13 at 19:58
  • With the state of PHP's multibyte string support you could probably spend a month digging into the why. :) – Chris Hayes Dec 29 '13 at 20:00

2 Answers2

3

There are a bunch of problems in your approach.

  1. If you're passing command line parameters, just on Windows alone, you have to be mindful about what your command may look like. Because you have a JSON encoded string, it's full of double quotes, spaces, and other characters that might be parsed differently when passed. The string might turn into individual arguments and end up in other array indexes. Here is a good reading: http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx

  2. Depending on the data passed, your small setup might be prone to shell injection (command-line injection).

  3. You will also have to test your code on various platforms; each OS has it's own quirks.

  4. By the looks of it, you may be spawning a new process on every request. It's a performance hit, and you'll probably discover in the future that this is unacceptable.


Alternatives

You can use PHP I/O streams (stdin/stdout). The documentation on those is very good for both PHP and NodeJS, and it's the recommended method for passing data between processes. For PHP, the docs are here: http://php.net/manual/en/features.commandline.io-streams.php For NodeJS, child processes would probably work: http://nodejs.org/api/child_process.html

Another suitable alternative (although more complicated) is to setup a server in Node on a random port, pass the port number as a command-line argument to PHP, and use a PHP script to connect to the NodeJS server via file_get_contents and get data from there via HTTP. To put back data, use a POST request via cURL functions in PHP.

I remember reading about a couple more ways to achieve it; one was with a FastCGI implementation, the other one involved memcached. I don't know much about those, but you can do your research and keep asking questions.

Silviu-Marian
  • 10,565
  • 6
  • 50
  • 72
  • Thanks for all the input, I'll have a look at the PHP commandline streams. I'm comfortable with that in node, but I do have almost no PHP experience at all. As far as performance hits go I wouldn't worry too much, this will probably be called once every two months (yet someone's gotta implement it :) ). – m90 Dec 29 '13 at 20:11
0

My problem stemmed from special characters (Umlauts like ä, ö or ü) in my JSON.

Using utf_8_encode on my input fixed the output of json_decode:

$data = json_decode(utf_8_encode($argv[1]), TRUE);

If anyone has input on the WHY I'd still be thankful as this does not make too much sense (everything already IS encoded in UTF-8).

m90
  • 11,434
  • 13
  • 62
  • 112