I'm currently working on a simple NodeJS client that connects to a PHP server using the net classes. In addition, the NodeJS client is working as a Socket.IO server that sends data received from the PHP server to the browsers connected with Socket.IO.
So far, everything is working fine. Yet if I connect with another client to Socket.IO, the PHP server has to send a notification to every connected client. Thus, it sends a JSON-encoded array to the NodeJS client which processes the JSON data (decoding and modifying it a bit).
Now the problem is that sometimes two separate messages sent by the PHP server are concatenated in NodeJS' onData event handling function:
client.on("data", function(data) {
var msgData = JSON.parse(data.toString("utf8"));
[...]
}
The variable data now sometimes (not every time!) contains two JSON-strings, such as:
{ "todo":"message", [...] } { "todo":"message", [...] }
This of course results in an exception thrown by the JSON.parse function. I expected two calls of the onData-function with the variable data being:
{ "todo":"message", [...] }
On the PHP server side I have to iterate over an array containing all Socket.IO-connections that are currently served:
foreach($sockets as $id => $client) {
$nodeJS->sendData($client, array("todo" => "message", [...]);
}
The $nodeJS->sendData-function json-encodes the array and sends it to the NodeJS client:
socket_write($nodeClient, json_encode($dataToSend));
The $nodeJS->sendData function is definitively called two times, as socket_write is.
I now have no idea whether PHP or NodeJS concatenates those two strings. What I want, is that NodeJS calls the onData-handler once for each time the $nodeJS->sendData function is called (e.g. sendData is called twice → the onData-event is fired twice).
I could of course add some flag at the end of each json-encoded string and later split them into an array in the onData function. However, I don't like that solution much.
Is there an easier way to accomplish this?
It's important to remember that when you're reading from a socket, the data is going to come in arbitrary chunks and its entirely up to your code to split them up into units that are meaningful to process; there is absolutely no guarantee that each chunk will correspond to one meaningful unit.
yannisgu has given you the first part of the solution (terminate each unit with a newline, so your code can tell where it ends): now you need to implement the second part, which is to buffer your incoming data and split it into units.
At initialization, do something like
var buf = '';
and set client's encoding to utf8.
In your "data" handler:
[UPDATED: incorporated josh3736's suggestions]
buf += data;
var idx;
while ((idx = buf.indexOf('\n')) >= 0) {
// there's at least one complete unit buffered up
var unit = buf.slice(0, idx);
// extract it
if (unit.slice(-1) == '\r') {
// CRLF delimited
unit = unit.slice(0, -1);
}
if (unit.length) {
// ignore empty strings
var msgData = JSON.parse(unit);
[...]
// process it
}
buf = buf.slice(idx +1);
// discard it
}
// at this point, buf is either empty or contains an incomplete
// unit which will be processed as soon as the rest of it comes in
Try to add a new line after the JSON-String on the PHP side.
Related
I'm having a curiosity issue and don't seem to find the correct phrases for expressing what I mean, for a successful Google search query.
Some sites (that mostly do price queries) do an ajax query to something (let's assume it's php script) with user set criteria and the data doesn't get displayed all at once when the query is finished, but you see some parts being displayed from the response earlier (as I assume they become available earlier) and some later.
I'd imagine the ajax request is done to a php script which in turn queries different sources and returns data as soon as possible, meaning quicker query responses get sent first.
Core question:
How would such mechanism be built that php script can return data
multiple times and ajax script doesn't just wait for A response?
I'm rather sure there's information about this available, but unfortunately have not been able to find out even by what terms to search for it.
EDIT:
I though of a good example being cheap flight ticket booking services, which query different sources and seem to output data as soon as it's available, meaning different offers from different airlines appear at different times.
Hope someone can relieve my curiosity.
Best,
Alari
On client side you need onprogress. See the following example (copied from this answer):
var xhr = new XMLHttpRequest()
xhr.open("GET", "/test/chunked", true)
xhr.onprogress = function () {
console.log("PROGRESS:", xhr.responseText)
}
xhr.send()
xhr.responseText will keep accumulating the response given by the server. The downside here is that xhr.responseText contains an accumulated response. You can use substring on it for getting only the current response.
On the server side, you could do output buffering to chunk the response, e.g. like:
<?php
header( 'Content-type: text/html; charset=utf-8' );
for($i = 0; $i < 100; $i++){
echo "Current Response is {$i} \r\n";
flush();
ob_flush();
// sleep for 2 seconds
sleep(2);
}
Is this achievable? If not, what are other ways in doing it best?
I'm trying to:
Return true after a successful function call is made.
Let the called function still execute even after return statement.
To make things clearer:
function foo() {
var $data; // a very large data
var $check = $this->bar($data); // gets true
if ($check) {
echo "FOO: Bar received my message!";
}
}
function bar($data) {
return true; // returns true, now foo doesn't care what bar will do
echo "BAR: returned true to foo, will now call foobar!";
// some code to process $data
$this->foobar(); // but hopefully still execute this line
}
function foobar() {
echo "FOOBAR: Hello, World!";
return;
}
Expected output: (asynchronously)
FOO: Bar received my message!
BAR: returned true to foo, will now call foobar!
FOOBAR: Hello, World!
What you are looking for is called "asynchronous" processing. Such thing exist in some languages, notably javascript, but not natively in php. There are some extensions, but they are not really widespread since this is a bit against the idea and strength of php.
Typically two alternative approaches are used, where the second option is by far the better one:
you send a normal response to the client and use phps ignore_client_abort feature. That feature allows to continue processing even after having sent a response. Note however that processing a higher amount of data in such synchronous manner is questionable: you most likely will run into some of the many php limits implemented for safety reasons. So yu would have to raise all those limits, which lowers your protection against miss use and bugs.
you use a job scheduler to store data processing jobs and notify the client about the fact that you received the data and created the processing jobs. Then you process each job in the queue one by one by means of a cronjob or similar, so independent of a client request. You get extra points if you implement a view on the queue state for the client :-)
There are frameworks for such things, basically what they do is to create entries in a database, one for each job. Then you have a single cron job fired periodically (every minute). That job checks if another job is already getting processed, if not it picks the next one and starts processing. Usually processing is done per php-cli calls to be independent from the web server environment. That also means you can even execute the jobs on a different system for a better performance. You have decoupled the processing from the web gui.
If you want to run more functions at the same time, PHP supports multi-threading. Here is a simple yet great example of what it can do: How can one use multi threading in PHP applications
Also, see http://php.net/manual/en/class.thread.php
I have an classical apache server delivering php files, and a nodeJS server (with socket.io, but whithout express/connect) used for real-time event management on that PHP website. I sometimes need to authenticate the clients connecting to the nodeJS server, but this authentication is lost when the user reloads the page, because it also reloads the socket.io client (I store the socket ID on the server, which gets lost at each refresh)
The question is: Is there a way to keep the connection alive in socket.io, or a way to link the apache PHP sessions and the nodeJS server? Or maybe a way to keep this authentication using cookies (knowing I must store sensitive data like user passwords and keys)?
You can use memcached as your session storage handler in PHP. Memcached is a simple key value store that can be accessed via TCP; there is a memcached module available for Node.js.
PHP stores the session in memcached by using the session id as the key. The session data (value) stored in memcached is a serialized PHP object, with a slight twist. You can read more about this unusual serialization at the SO question "Parse PHP Session in Javascript". Luckily though, there is already an NPM module out there: php-unserialize.
Now for the How-To.
Assumptions
memcached is accessible at 127.0.0.1:11211
php.ini (or php.d/memcache.ini) is configured with: session.save_handler='memcached' and session.save_path='tcp://127.0.0.1:11211'
you have installed the required NPM modules (2): npm install memcached php-unserialize
you're ok with CLI
Prepare
First, just to get some test data to work with, save the following php script (s.php):
<?php
session_start();
$_SESSION['some'] = 'thing';
echo session_id()."\n";
print_r($_SESSION);
Execute it with php s.php, and it should put stuff in stdout:
74ibpvem1no6ssros60om3mlo5
Array
(
[some] => thing
)
Ok, now we know the session id (74ibpvem1no6ssros60om3mlo5), and have confirmed that the session data was set. To confirm it is in memcached, you can run memcached-tool 127.0.0.1:11211 dump which provides a dump of known key:value pairs, for example I have two in my test bed:
Dumping memcache contents
Number of buckets: 1
Number of items : 3
Dumping bucket 2 - 3 total items
add 74ibpvem1no6ssros60om3mlo5 0 1403169638 17
some|s:5:"thing";
add 01kims55ut0ukcko87ufh9dpv5 0 1403168854 17
some|s:5:"thing";
So far we have 1) created a session id in php, 2) stored session data from php in memcached, and 3) confirmed the data exists via CLI.
Retrieval with Node.js
This part is actually really easy. Most of the heavy-lifting has already been done by the NPM modules. I cooked up a little Node.js script that runs via CLI, but you get the picture:
var Memcached = require('memcached');
var PHPUnserialize = require('php-unserialize');
var mem = new Memcached('127.0.0.1:11211'); // connect to local memcached
var key = process.argv[2]; // get from CLI arg
console.log('fetching data with key:',key);
mem.get(key,function(err,data) { // fetch by key
if ( err ) return console.error(err); // if there was an error
if ( data === false ) return console.error('could not retrieve data'); // data is boolean false when the key does not exist
console.log('raw data:',data); // show raw data
var o = PHPUnserialize.unserializeSession(data); // decode session data
console.log('parsed obj:',o); // show unserialized object
});
Assuming the above is saved as m.js, it can be run with node m.js 74ibpvem1no6ssros60om3mlo5 which will output something like:
fetching data with key: 74ibpvem1no6ssros60om3mlo5
raw data: some|s:5:"thing";
parsed obj: { some: 'thing' }
Warnings/Gotchas
One of my PHP applications stores some binary data in the session values (i.e. encrypted), but the keys and the normal session object remain intact (as in the example above). In this case, memcached-tool <host:port> dump printed a malformed serialized session string to stdout; I thought this might be isolated to stdout, but I was wrong. When using PHPUnserialize.unserializeSession, it also had trouble parsing the data (delimited by |). I tried a few other session deserialization methods out on the net, but did not have any success. I would assume memcached is maintaining the correct data internally since it works with the native PHP session save handler, so, at the time of this writing, I'm not quite sure if it is the deserialization methods or if the memcached NPM module simply isn't retrieving/interpreting the data correctly. When sticking with non-binary data like ascii or utf-8, it should work as intended.
I think this link will be of some help to you
https://simplapi.wordpress.com/2012/04/11/php-nodejs-session-share-memcache/
Though the thread is old I would like to recommend what I used for my project.
Instead of memcached you can also use Redis for session handling.
I have used the phpredis as php redis client.Instead of storing session to files you can save in Redis. Most of the heavy lifting will be done by apache. For every request apache will append the session values to the cookies.And it reads the session values from every request and validates it.
Setting required to save the php session to redis is also very simple.
session.save_handler = redis
session.save_path = "tcp://host1:6379?weight=1, tcp://host2:6379?weight=2&timeout=2.5, tcp://host3:6379?weight=2"
That's it.This will make php save the sessions to redis instead of the file. This will also move the session that are stored in files to redis.
If your project stores session in database - some do - then you can consider using database as a transfer medium.
If analysis in your particular case shows promise, then node-mysql (or similar) can be used - see this: link
The answer from zamnuts helped me make since of doing authentication and was the approach I was already taking. Thanks for that.
The reason I am posting is the for me some reason when using :
var PHPUnserialize = require('php-unserialize');
Kept giving me error
SyntaxError: String length mismatch
I am not sure why? I wrote a function that does the job for me and wanted to share in case it may help someone else.
function Unserialize(data){
var result = {};
if(data !== undefined){
var preg = data.replace(/(^|s:[0-9]+:)|(^|i:)|(^|b:)|(")|(;$)/g,'').split(';');
var a = [];
preg.forEach(function(value){
a.push(value.split('|'));
});
var b = [];
a.forEach(function(value){
if(Array.isArray(value)){
Array.prototype.push.apply(b, value);
}else{
b.push(value);
}
});
var arr_A = [];
var arr_B = [];
b.forEach(function(value, k){
if(k % 2 == 0){
arr_A.push(value);
}else{
arr_B.push(value);
}
});
if (arr_A == null) return {};
for (var i = 0, l = arr_A.length; i < l; i++) {
if (arr_B) {
result[arr_A[i]] = arr_B[i];
} else {
result[arr_A[i][0]] = arr_A[i][1];
}
}
}
return result;
}
I just call it like this:
var PHPUnserialize = Unserialize;
memcached.get(key, function(err, data){
var memData = PHPUnserialize(data);
console.log(memData.is_logged_in);
});
You should be able to modify the regex to suit your needs fairly easily.
I am trying to write a wrapper around a simulator which provides a web API so that users can spawn off simulations on a server and collect the results.
My initial design was to have a php simulation StartSimulation.php running in Apache which will fork & exec the simulation, and pipe the results to a file. However, you cannot fork & exec in php inside an apache module. Furthermore, it gets a bit messy in this implementation because there is no processes managing the orphaned simulations, so it is tricky to kill them and count them. It seems a bit difficult to use a standard web server since there is no global state which stores the list of running processes (simulations).
The simulator is written in c++, but It should be modified as little as possible. I prefer to write a wrapper for it and exec the simulator and capture its stdout and make that accessible to the user.
Basically, the wrapper should have an web-accessible API with 3 commands.
1.) start_simulation - which basically forks & execs an instance of the simulator, recording its pid in a table, and piping its stdout to a known buffer. The wrapper should not allow more than 16 instances of the simulator to run on the server. If successful, it returns a simulation code to the user. Otherwise, it returns an error code.
2.) stop simuation - takes the simulation code returned in (1), and kills the associated process.
3.) get_process - takes the simulation code returned in (1), looks up the known buffer which holds the stdout for that process, and returns that information to the user.
Should I write a custom application server for this? If so, is there a nice package with some starter code?
Thanks
Kyle
I know this is an old question but hopefully this will still prove helpful to somebody...
Having the process management (fork/exec/wait/kill/signal etc.) in a PHP script called directly from Apache via an http request is definitely not the way to go. As you say, it gets messy very quickly :)
I would suggest that the PHP script called via http is simply a command proxy to a simple server process. If PHP is your preferred language, you can implement both this way.
For example, you can do this with message queues as follows...
You can create a fairly simple PHP server that creates a message queue and wait for
messages to come in. It can then do the work of starting or stopping simulator processes
The remote user selects an operation (start, stop, get output) via a web page form.
This results in an HTTP/POST request sending the form data to your PHP script (I'd do this as an AJAX call so I can send the data and interpret the result without reloading the page)
Your server-side PHP script can interpret the form data and send a command via a message to the PHP server process
Let's illustrate this with some PHP code. I'm keeping this trivial and unsophisticated in the interests of brevity.
PHP Script (web form target)
This is where we interpret our incoming form request and turn it into a message for the server process
<?php
/*
* Responses are sent as simple text strings to be interpreted by
* the client-side JavaScript handling this AJAX call. Responses
* starting with 'ERR:' are errors, responses starting with 'ACK:'
* are acknowledgements. Simply check the first few characters of
* the response in the client-side JavaScript.
*/
header('Content-Type: text/plain; charset=UTF-8);
/*
* Here we define some message types, one per command. These should correspond
* to the command string sent from the web form
*/
$command = array(
'START_SIM' => 1,
'STOP_SIM' => 2,
'GET_STATUS' => 3,
'GET_OUTOUT' => 4
);
$queue_id = 0xbeef; /* An arbitrary message queue id */
$cmd = $_REQUEST['command']; /* The command from the web form */
/* get simulator instance id to act upon, if specified */
if (isset($_REQUEST['id']))
$sim_id = $_REQUEST['id'];
else
$sim_id = ''; /* no sim id? probably a create command */
/* check the message queue exists... */
if (msg_queue_exists($queue_id) === false) {
echo 'ERR:Message queue not found!';
return;
}
/* open the message queue and pass the command on to the server... */
if (($qhandle = msg_get_queue($queue_id)) === false) {
echo 'ERR:Failed to open message queue to server';
return;
}
if (msg_send($qhandle, $command[$cmd], $sim_id) === false)
echo 'ERR:Failed to send command';
else
echo 'ACK:Command sent ok';
?>
PHP Server (run separately on your web server)
And here's an equally simple server...
<?php
/*
* assume the same queue id's and defines as in the
* client code above, etc..
*/
if (($qhandle = msg_get_queue($queue_id)) === false) {
/* emit failure message to log file etc.. */
...
return;
}
while (1) {
if (msg_receive($qhandle, 0, $msgtype, $message,
true, 0, $rc) === false) {
/* log error message ... */
} else {
/*
* Get the client id (in case you want to send
* a reply back to the client) and the
* message data, which is the simulation id.
*
* Remember that we use the message type to
* indicate the command being requested
*/
$client = $message['client'];
$sim_id = $message['msg'];
evaluate_command($client, $msgtype, $sim_id);
}
}
?>
Obviously this is horribly simple, has no error checking and you'll need to write the "evaluate_command()" function yourself. I've just scribbled this down to illustrate the idea (and I've written this off the cuff, so it may be replete with other errors too!)
I have a continuously generated data (text file) generated by a program on the server. I want to plot the data as a real-time graph just like powergrid does. This was my approach:
As the data is generated continuously on the server in a text file, I wrote a PHP script which reads that file(get_file_contents), outputs the data points and plot the graph using sparkline jQuery plugin. But the problem is that it reads the file all at once. Moreover, the text file keeps on growing. Can anyone suggest me a better approach?
As you're talking about using a Javascript plotting solution you do the following:
on page load you create the current graph by reading the complete text file and remembering it's size.
after the page is loaded you create a Javascript function that regularly polls a specific script on your server using AJAX-techniques (XMLHttpRequest) and passing the last-known filesize of your text file as a parameter.
your polling script takes the filesize parameter, opens the text file, skips through the file until it reaches the point from which you last read the file (filesize-parameter).
the polling script returns all the available data from filesize to the end of the file and the new filesite
your Javascript reads in the AJAX response and adds the required plot points to your graph
you can then start over polling your server-side script with the new filesize as a parameter
This procedure involves server-side as well as client-side programming but can be accomplished easily.
The following is a sample polling script that requires a index paramater that tells the script from which position to read the text file and returns a JSON-encoded list of plot points and the new index pointer.
// poll.php
$index = (isset($_GET['index'])) ? (int)$_GET['index'] : 0;
$file = fopen('path/to/your/file.txt', 'r');
$data = array(
'index' => null,
'data' => array()
);
// move forward to the designated position
fseek($file, $index, SEEK_SET);
while (!feof($file)) {
/*
* assuming we have a file that looks like
* 0,10
* 1,15
* 2,12
* ...
*/
list($x, $y) = explode(',', trim(fgets($handle)), 2);
$data['data'][] = array('x' => $x, 'y' => $y);
}
// set the new index
$data['index'] = ftell($file);
fclose($file);
header('Content-Type: application/json');
echo json_encode($data);
exit();
The corresponding Javascript/jQuery snippet could be:
// the jQuery code to poll the script
var current = 0;
function pollData() {
$.getJSON('poll.php', { 'index': current }, function(data) {
current = data.index;
for (var i= 0; i < data.data.length; i++) {
var x = data.data[i].x;
var y = data.data[i].y;
// do your plotting here
}
});
}
// call pollData() every 5 seconds
var timer = window.setInterval(pollData, 5000);
Please be careful that this is only an example and that it lacks all error checking (e.g. concurrent calls to pollData() on the same page will be problematic).
It sounds like you have the visualization part mostly worked out. If the dataset is too large to re-calculate, you may want to look into techniques for maintaining incremental histograms. Here are a few papers that may help:
The history of histograms (abridged)
Random Sampling for Histogram Construction: How much is enough?
Data-Streams and histograms
Fast Incremental Maintenance of Approximate Histograms
First off, I would not generate the graph on the user side. That has simple reasons: Not everyone has JavaScript enabled (okay, depends on your target group) and it is probably not very fast.
Since you are already using PHP, I would therefore recommend using a package like pChart for creating the graphs on the server side. Another positive side-effect of this is that said package comes with caching, too. This would, for example, allow you to create the graph only when the data text file is changed (assuming you generate that with PHP, too - else you can simply check if the file was modified every time your PHP script is run) and thus saving loads of resources ;)