How increases the speed Ajax-php-xml chat application? - php

I made chat application using Ajax-php-xml technology. It work fine if the number of users below 50.
otherwise speed of application dramatically decreases. I want to manage 200s users at a time.
my XML format is
<?xml version="1.0" encoding="utf-8"?>
<messageData>
<message>
<sender>user__5338</sender>
<receiver>user__5339</receiver>
<content>hello</content>
<date_time>2012-08-17 09:24:57</date_time>
<status>unread</status>
</message>
<message>
<sender>user__5338</sender>
<receiver>user__5339</receiver>
<content>hello</content>
<date_time>2012-08-17 09:26:21</date_time>
<status>unread</status>
</message>
</messageData>
In my php, I fetch data from xml file using this method
$xml = simplexml_load_file($this->xml_file);
foreach($xml->message as $chat_data){
if($chat_data->status =='unread' && $chat_data->receiver ==$username){
$chat_data->status = 'read';
$xml->asXML($this->xml_file);
$sender =(string)$chat_data->sender;
$chat['message'] = (string)$chat_data->content;
$chat['date'] = (string)$chat_data->date_time;
}
}
How can inrease the speed of chat application? Can i increase the speed by using node js?

Why don't you use json as ajax transfer data type? I believe it might be faster, because php doesn't need to parse xml. And use jQuery as javascript library for your ajax requests, it is one of the best. It supports json. And use this tutorial as an example.
And one more thing, set the interval between ajax requests to 1-3 seconds. Maybe even more.

using sockets could increase your communication speed for sure , it may sound complicated but for your purpose it's the answer.
sockets are :
The WebSocket specification defines an API establishing "socket"
connections between a web browser and a server. In plain words: There
is an persistent connection between the client and the server and both
parties can start sending data at any time.
simple example :
var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);
// When the connection is open, send some data to the server
connection.onopen = function () {
connection.send('Ping'); // Send the message 'Ping' to the server
};
// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
// Log messages from the server
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};
searching will give your more examples

Related

Reactphp can't get total data on stream

im using reactphp library , and im working with a device that sends packages in different sizes. My problem is when i get the data
$stream->on('data', function ($data, React\Stream\ReadableStreamInterface $stream) {
$this->respuesta .= $data;
$stream->close();
});
I only get a part of the first package. Is there a way to keep waiting until the device sends all the data?
Here, on the wireshark capture the last package is the one that i cant get with react.
$loop = React\EventLoop\Factory::create();
$dnsResolverFactory = new React\Dns\Resolver\Factory();
$dns = $dnsResolverFactory->createCached('8.8.8.8', $loop);
$connector = new React\SocketClient\Connector($loop, $dns);
$connector->create($this->host, $this->port)->then(function (React\Stream\Stream $stream) use ($hex) {
$stream->write($hex);
$stream->on('data', function ($data, React\Stream\ReadableStreamInterface $stream) {
$this->respuesta .= $data;
$stream->close();
});
});
$loop->run();
It appears you are closing the connection right after receiving the data... You should keep this connection open until after you receive all of the data. The data event is dispatched after receiving some data, not all data.
Typically this is implementation specific, if your dealing with RPC style api, the client sending the request may not care about acknowledgment from the service and cut the connection after sending the data; in this case you should accumulate your buffer on the data event, and then process it on the end event.
If you want to keep the connection open, and send discrete chunks of information, typically you either lead the data package with the size of the package, allowing you to know how much of the buffer to fill before processing, or you can send a delimiter (typically a null byte) that marks the end of the package.

Sending messages from PHP to Node.js

How to send messages from php to node.js? I have a linux server running php and node.js.
When a user completes a transaction (via php), I'd like send a message from php to node.js. Node will then update the client via a socket connection.
What's a good way to send a small amount of data from php to node.js without defeating the performance of node.js?
The suggestion seems to be to talk to node through the HTTP interface, just as any other client does. You can talk to node via HTTP using cURL in php
See: http://groups.google.com/group/socket_io/browse_thread/thread/74a76896d2b72ccc/216933a076ac2595?pli=1
In particular, see this post from Matt Pardee
I faced a similar problem with wanting to keep users informed of a new
note added on to a bug, and similar notifications that could really
only be effectively sent from PHP to my Node server. What I did
follows (apologies if this gets all garbled and unformatted in
sending, if it does, I'd be happy to paste the code somewhere else):
First, you'll need to use cURL from PHP. I wrote a function for my
class like this:
function notifyNode($type, $project_id, $from_user, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1');
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
curl_setopt($ch, CURLOPT_PORT, 8001);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($ch, CURLOPT_POST, true);
$pf = array('f' => $type, 'pid' => $project_id, 'user_from' => $from_user,
'data' => array());
foreach($data as $k => $v) {
$pf['data'][$k] = $v;
}
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($pf));
curl_exec($ch);
curl_close($ch);
}
You'll notice that I send the cURL request on the same server since
both PHP and NodeJS are running there, your mileage may vary. The port
I set this code to connect to is 8001 (this is the port my Node server
is running on, and the port the socket.io server connects to). This
sends a HTTP POST request with the post field encoded. This is all
pretty standard cURL stuff.
In your Node app you probably have something like:
var server = http.createServer(function(req, res) {});
server.listen(8001);
var io = io.listen(server, { transports: ['websocket', 'flashsocket', 'xhr-polling'] });
...
well what we'll do here is expand on the http.createServer part, to
listen for connections coming from our local host ("127.0.0.1"). The
createServer code then becomes:
var server = http.createServer(function(req, res) {
// Check for notices from PHP
if(res.socket.remoteAddress == '127.0.0.1') {
if(req.method == 'POST') {
// The server is trying to send us an activity message
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
res.writeHead(200, [[ "Content-Type", "text/plain"]
, ["Content-Length", 0]
]);
res.write('');
res.end();
//sys.puts(sys.inspect({fields: fields}, true, 4));
handleServerNotice(fields);
});
}
}
});
From there you can implement your handleServerNotice function..
function handleServerNotice(data) {
...
}
etc etc. I haven't tested this in a while, and in fact that code block
was commented out on my node server, so I hope what I've pasted here
works - in general this concept is proven and I think it'll work for
you. Anyway just wanted to be sure you knew it's been a few months so
I'm not sure exactly why I commented out. The code I wrote took a
little research -- like setting the 'Expect:' header in cURL -- and I
was pretty excited when it finally worked. Let me know if you need any
additional help.
Best,
Matt Pardee
A bit late, but you could communicate with your node client using the Redis Pub/Sub mechanism in a very simple and effective way. All you need to do is install redis on your server.
On the php side, initialize Redis then publish a message
$purchase_info = json_encode(array('user_id' =>$user_id,
'purchase_information'=>array('item'=>'book','price'=>'2$'));
$this->redis->publish('transaction_completed', $purchase_info);
On the node.js side
var redis = require('redis');
var purchase_listener = redis.createClient();
purchase_listener.subscribe('transaction_completed');
purchase_listener.on('message', function(channel, message){
var purchase_data = JSON.parse(message);
user_id = purchase_data.user_id;
purchase_info = purchase_data.purchase_information;
// Process the data
// And send confirmation to your client via a socket connection
})
Is this scalable ? (In response to #mohan-singh)
When talking about scalability you need to think about your infrastructure's architecture and your particular needs but here's a quick answer :
I've been using a variant of this mechanism on a high traffic real-time application without problems but here's what you should be careful about:
Redis PUB/SUB is not a queuing system, that means if your node process goes down all the messages that were sent WHILE it is down will be lost.
If you have more than 1 subscriber to the publisher they will all receive the same message and handle it, be careful about that if you have more than a node process listening to the same redis db handling your real-time logic (There are easy ways to go around this though)
The nice thing about this system is that you don't need to add anything to your existing infrastructure and can get started immediately, it's very fast and it behaves exactly like an HTTP server.
Here are your alternatives for more scalable options:
Using a self-hosted fast messaging queue server (ActiveMQ, RabbitMQ, beanstalkd ... ) server to handle your messaging logic between php and node, these tend to be fast but as the load increases you lose a bit of performance, and have to maintain/scale your messaging servers, and take care of duplication across regions which is not an easy and enjoyable thing (depending on what you enjoy doing).
Using a hosted messaging queue server (IronMQ, SQS...) Some of these(IronMQ) are pretty fast and will be great for your use case but introduce some (minor) complexity to your codebase.
Building a messaging queue with Redis with clustered node servers : https://davidmarquis.wordpress.com/2013/01/03/reliable-delivery-message-queues-with-redis/
Using HTTP inside a VPN to communicate with node servers. Once you see your traffic spiking you will only need to load-balance your node servers and add as much stateless servers as you need and send POST messages to that load balancer.
The point of this lengthy edit is that there is no such thing as a magic scalable solution, you need to weigh your options and see which one works the best for your use case.
In my opinion, if you're starting to build your first iteration now, choose any option that you're comfortable with, write very clean code and when you start scaling it will be very easy to change, this is what I've done :)
I found such problem can be solved simply by using the Express framework.
Let's suppose php sends a json message to the node server and the server replies with ok.
In app.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var bodyParser = require('body-parser')
app.use(bodyParser.json());
app.post('/phpcallback', function(req, res) {
var content = req.body;
console.log('message received from php: ' + content.msg);
//to-do: forward the message to the connected nodes.
res.end('ok');
});
http.listen(8080, function(){
var addr = http.address();
console.log('app listening on ' + addr.address + ':' + addr.port);
});
In test.php
<?php
$data = array("name" => "Robot", "msg" => "Hi guys, I'm a PHP bot !");
$data_string = json_encode($data);
$ch = curl_init('http://localhost:8080/phpcallback');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($data_string))
);
echo curl_exec($ch)."\n";
curl_close($ch);
?>
Here we have also a more detailed example where a php script could drop a message to the users of a specific chat room.
https://github.com/lteu/chat
My personal impression about Redis approach: Cumbersome. You need to run Apache, nodeJS and Redis, three servers together in the same. And PubSub mechanism is quite different from the emit of socket.io, so you need to see if it is compatible with your existing code.
I was looking for a really simple way to get PHP to send a socket.io message to clients.
This doesn't require any additional PHP libraries - it just uses sockets.
Instead of trying to connect to the websocket interface like so many other solutions, just connect to the node.js server and use .on('data') to receive the message.
Then, socket.io can forward it along to clients.
Detect a connection from your PHP server in Node.js like this:
//You might have something like this - just included to show object setup
var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server);
server.on("connection", function(s) {
//If connection is from our server (localhost)
if(s.remoteAddress == "::ffff:127.0.0.1") {
s.on('data', function(buf) {
var js = JSON.parse(buf);
io.emit(js.msg,js.data); //Send the msg to socket.io clients
});
}
});
Here's the incredibly simple php code - I wrapped it in a function - you may come up with something better.
Note that 8080 is the port to my Node.js server - you may want to change.
function sio_message($message, $data) {
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$result = socket_connect($socket, '127.0.0.1', 8080);
if(!$result) {
die('cannot connect '.socket_strerror(socket_last_error()).PHP_EOL);
}
$bytes = socket_write($socket, json_encode(Array("msg" => $message, "data" => $data)));
socket_close($socket);
}
You can use it like this:
sio_message("chat message","Hello from PHP!");
You can also send arrays which are converted to json and passed along to clients.
sio_message("DataUpdate",Array("Data1" => "something", "Data2" => "something else"));
This is a useful way to "trust" that your clients are getting legitimate messages from the server.
You can also have PHP pass along database updates without having hundreds of clients query the database.
I wish I'd found this sooner - hope this helps! 😉
We do it by using message queue. There are a lot of solutions like radis (https://github.com/mranney/node_redis) or 0mq (http://zeromq.org/). It allows to send a message to subscribers (for example from php to nodejs).
Step 1. Get the PHP Emitter:
https://github.com/rase-/socket.io-php-emitter
$redis = new \Redis(); // Using the Redis extension provided client
$redis->connect('127.0.0.1', '6379');
$emitter = new SocketIO\Emitter($redis);
$emitter->emit('new question', '<b>h<br/>tml</b>');
add this to your index.js:
var redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6379 }));
io.on('connection', function(socket){
socket.on('new question', function(msg) {
io.emit('new question', msg);
});
});
add something like this to your index.html
socket.on('new question', function(msg) {
$('body').append( msg );
});

Decoding network chars (HTML5 Websocket)

I'm trying to develop a webchat with HTML5 websocket (with hybi-17 protocol) but I've some problems with chars decoding.
This is what I send through the client (user-agent: Firefox 7):
var socket = new MozWebSocket ('ws://localhost/server.php');
socket.onopen = function () {
alert ('Opened!');
}
Then, I send these data:
socket.send ('Hello');
socket.send ('World');
And this is the server-side code:
$bytes = #socket_recv ($socket, $buffer, BUFSIZE, 0);
if (($bytes == 0) || ($bytes == 2)) {
this->disconnect ($socket);
}
else {
echo $buffer;
}
While this is the data recevied echoed:
��6S~g?Y (Hello)
���~����� (World)
As you can see, the socket is opened and data travels from the client to the server.
The server works with PHP5 and uses normal socket functions to build the connection.
How can I decode that unreadable string in a human readable one?
Thanks in advance.
You have made one of the most common errors people make when they first start writing code that uses TCP -- you forgot to implement the protocol!
In your case, you forgot it in the server. The client already has a WebSocket implementation, and you request it by creating a 'MozWebSocket' object. The WebSocket specification says, "Each frame starts with a 0x00 byte, ends with a 0xFF byte, and contains UTF-8 data in between." Where's the code in the server to find the start of a frame and the end of a frame? Where the code to discard the 0xFF byte?
You actually have to implement the protocol. The protocol specification tells you how to decode the received data. (In your case, the data you are seeing as junk is most likely part of the protocol handshake -- the part that looks like ^n:ds[4U in this description of the handkshake phase.)
I'm pretty sure your method of invoking a PHP script to handle the WebSocket call through the web server will not work. That is, unless your web server knows how to do this -- WaterSpout and phpdaemon do.
Using the base server.php and client.html from http://code.google.com/p/phpwebsocket/ along with modification from HTML5 WebSocket with hybi-17 to deal with the single key standard I can successfully send one message to the server before it closes unexpectedly. It's at least a step closer just not sure as of yet why it closes after one successful message.

Using PHP soap service with Delphi without WSDL?

I'm quite familiar with using web services in Delphi when I have a WSDL. I simply use the wizard and in a few secs I'm up and running.
I now have a challenge where I'm given a soap interface written in PHP, without any WSDL schema.
The sample given to me for PHP is:
<?php
// The xml to be sent to the webService
$reqest_string = <<<XML
<test_api>
<request>1</request>
</test_api>
XML;
// create web service client
$client = new WSClient(array("to" => "http://api.infax.co.za/edge_api.php"));
// send request to the web service
$reply = $client->request($reqest_string);
// display the responce from the webservice
$xml_str = simplexml_load_string($reply->str);
// display response on screen
echo "Came from server = ".$xml_str->response."<br>";
?>
I've tried just post-ing the xml to the url, but I get a soap error back about a function that does not exist.
Any ideas??
For very simple SOAP web services, it could be easier to follow existing examples / documentation or (if neither is good enough) record the interaction using a HTTP proxy (fiddler2), and then code the communciation using a XML library of your choice.

PHP web service, send response before end of script execution

I have a web service written in PHP to which an iPhone app connects to. When the app calls the service, a series of notification messages are sent to Apple's APNs server so it can then send Push Notifications to other users of the app.
This process can be time consuming in some cases and my app has to wait a long time before getting a response. The response is totally independent of the result of the notification messages being sent to the APNs server.
Therefore, I would like the web service to send the response back to the app regardless of whether the messages to APNs have been sent.
I tried using pcntl_fork to solve the problem:
<?php
...
$pid = pcntl_fork();
if($pid == -1)
{
// Could not fork (send response anyway)
echo "response";
}
else if($pid)
{
// Parent process - send response to app
echo "response";
}
else
{
// Child process - send messages to APNs then die
sendMessageAPNs($token_array);
die();
}
?> // end of script
Unfortunately, the parent process seems to wait for the child process to end before sending the response even though I do not use pcntl_wait in the parent process. Am I doing something wrong or is this normal behaviour? If this is normal then is there another way I can solve this problem?
Thank you!
If you're hosting the PHP process in Apache then you really shouldn't use this: see this for the section that says *Process Control should not be enabled within a web server environment and unexpected results may happen if any Process Control functions are used within a web server environment. *.
You should probably set up a separate daemon in your preferred language of choice and hand the APNS communication tasks off to that. If you really really really must try using ob_flush().
I think you can send the response back before doing the "long" process. Take a look at the flush() function of PHP it'll maybe help

Categories