PHP Packets to a minecraft server? - php

Source for packet format: http://wiki.vg/Protocol
I am trying to write a program in php which will send packets to a minecraft server I host. This will likely be for a multiplayer implementation for phones, which do not support the same API formats. The code i have below is my failed attempt to make this work. How can i do this properly? The server is recognizing something, but its either not sending anything back, or something. This below is supposed to send 0x00, the handshake packet to request the stats on the server using the next state ID: 1. Minecraft should be responding with the same ID, but with the server motd, and the player count. For 1.7.2, which this will be for, it'll also send a server-icon.png. But i can safely ignore that data, as it'll be direct connections only.
What am I doing wrong, and how can I fix it?
Main.php
require("socket.php");
$f = getStat("zontreck.dyndns.biz",25565);
/*$za = 0x00;
$za[0] = 74;
$za[1] = "zontreck.dyndns.biz";
$za[2] = 25565;
$za[3] = 1;
*/
$za = array(0x00,"Protocol Version"=>73,
"Server Address"=>"zontreck.dyndns.biz",
"Server Port"=>25565,
"Next State"=>1);
$dd = doWrite(pack("a",$za),$f);
echo("Response from doWrite: " .$dd."\n");
echo("Sending: " . pack("a",$za)."\n");
/*if(doWrite(pack("a",$za),$f))
{
echo(fgets($f));
} else {
echo(fgets($f));
}*/
$ff = fgets($f);
//$u = unpack("a",$ff);
fclose($f);
echo("Data from server: " . $ff."\n");
echo("Data from server length: " . strlen($ff)."\n");
//fclose($f);
?>
socket.php
<?
function getStat($url = "",$port=25565)
{
$f = fsockopen($url,$port);
return $f;
}
function doWrite($packet,$socket)
{
return fwrite($socket,$packet);
}
?>
Output from main.php
root#zontreck:/var/www/slmc# php main.php
PHP Notice: Array to string conversion in /var/www/slmc/main.php on line 16
Response from doWrite: 1
PHP Notice: Array to string conversion in /var/www/slmc/main.php on line 18
Sending: A
Data from server:
Data from server length: 0
root#zontreck:/var/www/slmc#

You'll probably want to take a look at this:
https://forums.bukkit.org/threads/web-php-simple-to-use-minecraft-server-status-query.144329/
It's basically some explanation on this library which does exactly what you want:
https://github.com/FunnyItsElmo/PHP-Minecraft-Server-Status-Query
It also uses sockets so you could always take some of the code and modify it to your needs, but I strongly advice you just to use the library as-is because it does what you're trying to accomplish.

Both of the commenters are right, you need to revisit how you are doing this.
More specifically, the Minecraft protocol uses UDP, which means you need to have access to the raw socket using socket_create - http://php.net/manual/en/function.socket-create.php
Then you need to build a string that contains all of the of the required packets correctly, as #Marc B outlined. Then you can write that string to the socket. Note that since UDP is both stateless and has no error correction, you will also have to write retry routines if you get an error back.
What you are currently doing is building data structures in one language (PHP), then trying to write them to a wire protocol (totally different), which is pretty much impossible.
It's certainly possible to do this in PHP, but you have to work at a much lower level than you are now doing, with raw sockets, hex data strings and network error handling. I would suggest you look at other PHP libraries which handle UDP data to see if there is some code you can reuse.
There is some code in the socket_create page comments that you might be able to use/learn from. In particular, there is a TFTP example which you might be able to modify.
Not a simple answer, but this is non-trivial to do in any language and PHP isn't really designed for this, so there aren't a lot of examples.

Related

Detecting peer disconnect (EOF) with PHP socket module

I'm having a weird issue with PHP's sockets library: I do not seem to be able to detect/distinguish server EOF, and my code is helplessly going into an infinite loop as a result.
Further explanation below; first of all, some context (there's nothing particularly fancy going on here):
<?php
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, '127.0.0.1', 8081);
for (;;) {
$read = [$socket];
$except = NULL;
$write = [];
print "Select <";
$n = socket_select($read, $write, $except, NULL);
print ">\n";
if (count($read)) {
print "New data: ";
#socket_recv($socket, $data, 1024, NULL);
$data = socket_read($socket, 1024);
print $data."\n";
}
print "Socket status: ".socket_strerror(socket_last_error())."\n";
}
The above code simply connects to a server and prints what it reads. It's a cut-down version of what I have in the small socket library I'm writing.
For testing, I'm currently using ncat -vvklp 8081 to bind a socket and be a server. With that running, I can fire up the code above and it connects and works - eg, I can type in the ncat window, and PHP receives it. (Sending data from PHP is working too, but I've excluded that code as it's not relevant.)
However, the moment I ^C ncat, the code above enters a hard infinite loop - and PHP says there's no error on the socket.
I am trying to figure out where the button is that whacks PHP upside the head and makes it realize that the peer has disconnected.
socket_get_status() is a great misnomer - it's an alias for stream_get_meta_data(), and it doesn't actually work on sockets!
feof() similarly spouts Warning: feof(): supplied resource is not a valid stream resource.
I can't find a socket_* function for detecting peer EOF.
One of the PHP manual notes for socket_read() initially dissuaded me from using that function so I used socket_recv() instead, but I eventually tried it just in case - but no dice; switching the receive call has no effect.
I have discovered that watching the socket for writing and then attempting to write to it will suddenly make PHP go "oh, wait, right" and start returning Broken pipe - but I'm not interested in writing to the server, I want to read from it!
Finally, regarding the commented part - I would far prefer to use PHP's builtin stream functionality, but the stream_* functions do not provide any means for handling asynchronous connect events (which I want to do, as I'm making multiple connections). I can do stream_socket_client(... STREAM_CLIENT_ASYNC_CONNECT ...) but then cannot find out when the connection has been established (6yo PHP bug #52811).
Okay, I figure I might as well turn the comments above into an answer. All credit goes to Ryan Vincent for helping my thick head figure this out :)
socket_recv will return 0 specifically if the peer has disconnected, or FALSE if any other network error has occurred.
For reference, in C, recv()'s return value is the length of the new data you've just received (which can be 0), or -1 to indicate an error condition (the value of which can be found in errno).
Using 0 to indicate an error condition (and just one arbitrary type of error condition, at that) is not standard and unique to PHP in all the wrong ways. Other network libraries don't work this way.
You need to to handle it like this.
$r = socket_recv($socket, $buf, $len);
if ($r === FALSE) {
// Find out what just happened with socket_last_error()
// (there's a great list of error codes in the comments at
// http://php.net/socket_last_error - considering/researching
// the ramifications of each condition is recommended)
} elseif ($r === 0) {
// The peer closed the connection. You need to handle this
// condition and clean up.
} else {
// You DO have data at this point.
// While unlikely, it's possible the remote peer has
// sent you data of 0 length; remember to use strlen($buf).
}

PHP fputs "waits" until the end of the script

Currently I am trying to develop a PHP script used as a publicly available part of a client/server application. The php script should be used to authenticate users with a one-time token.
The other part of the application is a java program, which offers a telnet socket for other applications to connect to. Authentication is done through this telnet connection.
The java part is already working - but I still have a huge problem with the PHP part.
In php, I have opened a connection to the telnet port of the java program, which works so far. After the connection is initialized, the java program waits for input from the PHP script in order to authenticate the user.
After the authentication process has been finished, it returns a String to the PHP script (or any other program connected to its telnet server) which the PHP script should output.
Before I explain my problem, this is the part of the PHP script where the actual communication happens:
$tnconn = fsockopen("localhost", 53135, $errno, $errstr, 2);
if(!$tnconn) {
echo "SERVER_UNAVAILABLE";
die();
} else {
$data = $p_ip." ".$p_name." ".$p_token;
fputs($tnconn, $data);
while (true) {
if(($telnet_response = fgets($tnconn)) == false) {
break;
}
}
}
echo $telnet_response;
It seems like the fputs() statement is executed after the loop even tho it should happen before it starts - else the java application couldn't get the data that is passed to the php script, but it is needed to authenticate users.
Right after the data was received, the telnet server would output the String to indicate whether authentication was successful or not.
I tried temporarily removing the loop and the data was successfully passed with fputs() so I assume php waits until the whole script is finished and then executes the function.
How can I make it send the data before the loop?
Thank you in advance.
The issue is probably that you need to send a \n at the end of your data string so the telnet server knows you have sent a full sequence of data. Otherwise it is most likely sitting there waiting for more input.
Try:
$data = $p_ip." ".$p_name." ".$p_token . "\n";

How to use winsock in C++ to pass $_get superglobal to a .php on localhost

I am trying to use a c++ script to pass some informations from this script to a local server (localhost) using a socket connection.
As I would like to interact with a DB and I am more comfortable with php, I would like to pass the data through $_GET superglobal sending the complete URL correctly and directly formatted with the $_GET[''] variables (not so much hack issues as I am on a stand alone machine).
I read many posts about using winsock2 for cpp, and I step by step implemented the examples in my cpp program but I am experiencing two troubles:
1) I put in the host structure the localhost through gethostbyname() function. I would like to be sure the ip adress is the correct one, but a printf of a converted-into-char host->h_addr sent me back something not looking like an ip_adress. Do you have any better way to see what host got by this function? Is it safe to use gethostbyname() on localhost?
2) I would like to know how I can correctly write the data to be sent to the server to perform the action on the database as would do the opening of the dedicated php web page. I am interested by the correct result, but would me much more interested by a complete and correct reference (website would be nice, or even book) to know what is the correct syntax for message send to the server on a socket.
Hereafter is my code:
SOCKET Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct hostent *host;
host = gethostbyname("localhost");
SOCKADDR_IN SockAddr;
SockAddr.sin_port = htons(80);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
printf("Connecting...\n");
if (connect(Socket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr)) != 0)
{
printf("Could not connect");
system("pause");
return 1;
}
else
{
printf("Connected!\n\n");
}
char url[100] = "GET / HTTP/1.1\r\nHost:localhost/CoffeeTime/remove.php?scard_ID=";
strcat(url, scardid);
strcat(url, "&remove=1\r\nConnection: close\r\n\r\n");
int url_len = strlen(url);
printf((char*)url);
printf("\n");
send(Socket, url, url_len, 0);
closesocket(Socket);
WSACleanup();
As you could see, nothing new under the sun, I took most of this code from someone on stackoverflow.
Thank you!
Facing the huge number of answers :) , I will try to give the best answer I could as I finally succeeded to reach my server through this connection.
The solution is only in the string sent to the server : as I use a XAMPP server I could easily see through Netstat that the connection is OK (gethostbyname works well with "localhost" in arg so no need to use inet_addr with a static localhost ip for people as noob as I am.
Looking at XAMPP apache server log and after opening the adressed php page I've seen at the end of the file the GET string and it is no need to give the /localhost/ before the complete link. Moreover, the GET string ends with HTTP 1.1 instead of starting with it.
Finally, my correct syntax is
char url[100] = "GET /CoffeeTime/remove.php?scard_ID=";
strcat(url, scardid);
strcat(url, "&remove=1\r\n74AD45C8&remove=1 HTTP/1.1 \r\n Connection: close\r\n\r\n");
So no big deal, no huge announcement but it can be interesting for people who use XAMPP to see more useful stuff going with the XAMPP control panel.
Thanks to the guy who downgrade me with no comment by the way :o) .

Reading data from serial port from Arduino on Windows via PHP. Data not matching serial monitor output

Data I send to the serial port from the Arduino Uno can be viewed exactly as expected in the Arduino serial monitor, but when reading the data from PHP through serproxy in my WAMP environment I am getting some missing or extra characters (often a character that looks like a question mark inside of a black diamond, for example).
I've found similar questions posted, but all of the answers fell short. Often solutions were given for Linux only, or solved only part of the many challenges it takes to even get Windows to read (not write) from a serial port.
I tried the following to get PHP to simply read any serial data:
I first tried the php_serial class suggested, but quickly found out it only allows writing on Windows, and the answer for one of the other stack overflow questions (Serial Communication Arduino to PHP) suggested replacement code only for the Linux portion of the code, not Windows.
The article at Serial comm with PHP on Windows
also mentions limited capacity on Windows for php_serial class and suggests an alternative serial extension (also mentioned here and here), but this would not load on my WAMP environment with PHP 5.4.12 VC9 build when I used the correct matching extension version, added the extension to the correct php.ini, and restarted the server. I received a "Module win_serial is not compiled into PHP" after following all of the steps. If anyone else has had this issue please let me know as I would be willing to look into this again.
Finally, I tried using a program called serproxy which redirects network sockets to and from serial ports. This does work with the caveat that I added a 10uF capacitor on the Arduino's GND and RESET pins to prevent reseting on new serial connections as mentioned at PHP serial port data return from Arduino.
So now, I have my Arduino sending data to my computer via the USB cable, and so long as I am monitoring the data in Arduino's serial monitor, everything looks as it should. The moment I echo out that same data in PHP I begin to see extra or missing data along with the stream. So sending the text "AOK AOK AOK" sometimes becomes "OK?Pz[R" or something similar when echoed out of my PHP script.
Things I've tried to get clean serial data from PHP socket_read():
Messed around with various mb_convert_encoding (like 'ASCII' or 'utf-8')
Setting parity of serial data. I tried setting it to "EVEN" in serproxy config and DOS (ran command of "mode COM4: BAUD=9600 PARITY=E data=8 stop=1 XON=off TO=on" and recieved a valid response/output that command worked as expected)
Verified baud rate is set to 9600 in PHP code and serproxy config
Attempted simple trimming and/or regular expressions to filter out noise, but it doesn't help as some normal alphanumeric characters are randomly mixed in the output as well
Having modified some example socket code for TCP/IP from php.net, I have a PHP script that writes 2048 bits of data from the serial port via serproxy. This page is called via jQuery from another page every 10th of a second and the echoed content is loaded into the contents of a on my main page.
My end goal is to send a stream of either 1's or 0's to be sent to my PHP script to indicate that a should toggle it's background color. I would prefer to be certain those 1's or 0's were not just randomly echoed among the extra characters and truly came from the serial stream itself.
Does anyone know if serproxy is the cause of the adding or removing the unwanted data that I'm seeing in PHP?
The fact that the serial monitor is showing the correct data indicates to me that it's something in the way PHP is receiving or parsing the data.
I'm running out of ideas on what else I could check. Maybe another pair of eyes on this will bring to light something I've overlooked or did incorrectly.
Please see my code below for specific examples below:
serial.html
<!DOCTYPE html>
<head>
</head>
<body>
<div id="serial" name="serial" class="serial"></div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script src="js/main.js"></script>
</body>
</html>
serial_output.php
<?php
// Set service port to 5334 for serproxy
$service_port = 5334;
// Using localhost address
$address = '127.0.0.1';
/* Create a TCP/IP socket. */
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
}
// Attempting to connect to '$address' on port '$service_port'...";
$result = socket_connect($socket, $address, $service_port);
if ($result === false) {
echo "socket_connect() failed.\nReason: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
}
// Read 2048 bits of data from socket and convert encoding to ASCII
$out = mb_convert_encoding(socket_read($socket, 2048), 'ASCII');
// Filter out anything that is not "AOK"
if(preg_match("/AOK/", $out)){
echo 1;
} else {
// Else output raw data so we can see what was actaully sent
echo $out;
}
// Closing socket...
socket_close($socket);
?>
main.js
// Set #serial background color to red when receiving a "1"
function setBgColor(){
var serial = $('#serial');
// Set #serial background color to red when receiving a "1"
if($('#serial').html() == "1") {
serial.css('background-color','red');
} else {
// Set #serial background to white if we did not receive a "1"
serial.css('background-color', 'white');
}
}
var intervalId = window.setInterval(function(){
$('#serial').load('serial_output.php');
setBgColor();
}, 100);
arduino_serial.ino
#include <avr/pgmspace.h>
void setup() {
// Initialize serial and wait for port to open:
// Currently I have parity on my serial port set to "EVEN" hence SERIAL_8E1
Serial.begin(9600, SERIAL_8E1);
}
void loop() {
Serial.println("AOK");
}
So I ran your code and had the same issues with my Arduino and an accelerometer. I found three ways to alleviate the issue.
First is just to error check your data in terms of what you expected. If the data doesn't match what you expected, just discard it. If you are getting data 10x a second, I suppose you can afford to lose some. [BTW: serproxy crashes on me in under 10 minutes, so it's of limited use to me].
Second, just delay the data on the Arduino side. Apparently the data loss is a "known issue" regarding Arduinos and serial ports. This person's site at martinmelchior.be has some code to delay the data stream being sent from the Ardunio;
`void slowSerialPrint(char text[]) {
for ( int i ; i < strlen(text) ; i ++ ) {
Serial.print(text[i]);
delay(5);
}
} `
Scroll down to "But not so fast..." to find that snippet.
Finally, you could just try what many others are doing and buy a cheap wireless router and use that as your own inexpensive wi-fi shield. Which, oddly enough is what the site linked above does!
It is also good to note that that router's maximum current draw at 5V is 185mA (OpenWrt boot), average current draw with WiFi at 18dBm is 100mA, without WiFi 80mA. Hence the average router power consumption is 0.5W, which is incredibly low.
Also, thank you for the code you posted, I was searching for a way to do exactly what you were doing, so I implemented your code, hit the same wall, solved my issue by slowing down the Arduino's output in javascript and discarding dirty data, then branched out into other options.
tl;dr: I don't think there is a simple solution.

Webbased chat in php without using database or file

I am trying to implement a realtime chat application using PHP . Is it possible to do it without using a persistent data storage like database or file . Basically what I need is a mediator written in PHP who
accepts messages from client browsers
Broadcasts the message to other clients
Forgets the message
You should check out Web Sockets of html5. It uses two way connection so you will not need any database or file. Any chat message comes to the server will directly sent to the other users browser without any Ajax call. But you need also to setup web socket server.
Web sockets are used in many real time applications as well. I am shortly planing to write full tutorial on that. I will notify you.
Just tried something I had never done before in response to this question. Seemed to work but I only tested it once. Instead of using a Socket I had an idea of using a shared Session variable. Basically I forced the Session_id to be the same value regardless of the user therefore they are all sharing the same data. From a quick test it seems to work. Here is what I did:
session_id('12345');
session_start();
$session_id = session_id();
$_SESSION['test'] = $_SESSION['test'] + 1;
echo "session: {$session_id} test: {$_SESSION['test']} <br />";
So my thought process was that you could simply store the chat info in a Session variable and force everyone regardless of who they are to use a shared session. Then you can simply use ajax to continually reload the current Session variable, and use ajax to edit the session variable when adding a message. Also you would probably want to set the Session to never expire or have a really long maxlifetime.
As I said I just played around with this for a few minutes to see if it would work.
You will want to use Sockets. This article will cover exactly what you want to do: http://devzone.zend.com/209/writing-socket-servers-in-php/
When I tried to solve the same problem, I went with Nginx's Push Module. I chose to go this way since I had to support older browsers (that usually won't support WebSockets) and had no confidence in setting up an appropriate solution like Socket.io behind a TCP proxy.
The workflow went like this:
The clients connect through long-polling to my /subscriber location, which is open to all.
The /publisher location only accepts connections from my own server
When a client subscribes and talks, it basically just asks a PHP script to handle whatever data is sent.
This script can do validation, authorization, and such, and then forwards (via curl) the message in a JSON format to the /publisher.
Nginx's Push Module handles sending the message back to the subscribers and the client establishes a new long-polling connection.
If I had to do this all over again, then I would definitely go the Socket.io route, as it has proper fallbacks to Comet-style long-polling and has great docs for both Client and Server scripts.
Hope this helps.
If you have a business need for PHP, then adding another language to the mix just means you then have two problems.
It is perfectly possible to run a permanent, constantly-running daemonised PHP IRCd server: I know, because I've done it, to make an online game which ran for years.
The IRC server part I used is a modified version of WaveIRCd:
http://sourceforge.net/projects/waveircd/
I daemonised it using code I made available here:
http://www.thudgame.com/node/254
That code might be overkill: I wrote it to be as rugged as I could, so it tries to daemonise using PHP's pcntl_fork(), then falls back to calling itself recursively in the background, then falls back to perl, and so on: it also handles the security restrictions of PHP's safe mode in case someone turns that on, and the security restrictions imposed by being called through cron.
You could probably strip it down to just a few lines: the bits with the comments "Daemon Rule..." - follow those rules, and you'll daemonize your process just fine.
In order to handle any unexpected daemon deaths, etc, I then ran that daemoniser every minute through cron, where it checked to see if the daemon was already running, and if so either quietly died, or if the daemon was nonresponsive, killed it and took its place.
Because of the whole distributed nature of IRC, it was nicely rugged, and gave me a multiplayer browser game with no downtime for a good few years until bit-rot ate the site a few months back. I should try to rewrite the front end in Flash and get it back up again someday, when I have time...
(I then ran another daemonizer for a PHP bot to manage the game itself, then had my game connect to it as a java applet, and talk to the bot to play the game, but that's irrelevant here).
Since WaveIRCd is no longer maintained, it's probably worth having a hunt around to find if anyone else has forked the project and is supporting it.
[2012 edit: that said, if you want your front end to be HTML5/Javascript, or if you want to connect through the same port that HTTP connects through, then your options are more limited than when using Flash or Java. In that case, take the advice of others, and use "WebSockets" (poor support in most current browsers) or the "Socket.io" project (which uses WebSockets, but falls back to Flash, or various other methods, depending what the browser has available).
The above is for situations where your host allows you to run a service on another port. In particular, many have explicit rules in their ToS against running an IRCd.]
[2019 edit: WebSockets are now widely supported, you should be fine using them. As a relevant case study, Slack is written in PHP (per https://slack.engineering/taking-php-seriously-cf7a60065329), and for some time supported the IRC protocol, though I believe that that has since been retired. As its main protocol, it uses an API based on JSON over WebSockets (https://api.slack.com/rtm). This all shows that a PHP IRCd can deliver enterprise-level performance and quality, even where the IRC protocol is translated to/from another one, which you'd expect to give poorer performance.]
You need to use some kind of storage as a buffer. It IS plausable not to use file or db (which also uses a file). You can try using php's shared memory functions, but I don't know any working solution so you'll have to do it from scratch.
Is it possible to do it without using a persistent data storage like
database or file?
It is possible but you shouldn't use. Database or file based doesn't slows down chat. It will be giving additional security to your chat application. You can make web based chat using ajax and sockets without persistent data.
You should see following posts:
Is database based chat room bad idea?
Will polling from a SQL DB instead of a file for chat application increase performance?
Using memcached as a database buffer for chat messages
persistent data in php question
https://stackoverflow.com/questions/6569754/how-can-i-develop-social-network-chat-without-using-a-database-for-storing-the-c
File vs database for storage efficiency in chat app
PHP is not a good fit for your requirements (in a normal setup like apache-php, fastcgi etc.), because the PHP script gets executed from top to bottom for every request and cannot maintain any state between the requests without the use of external services or databases/files (Except e.g. http://php.net/manual/de/book.apc.php, but it is not intended for implementing a chat and will not scale to multiple servers.)
You should definitely look at Node.js and especially the Node.js module Socket.IO (A Websocket library). It's incredibly easy to use and rocks. Socket.IO can also scale to multiple chat servers with an optional redis backend, which means it's easier to scale.
Trying to use $_SESSION with a static session id as communication channel is not a solution by the way, because PHP saves the session data into files.
One solution to achieving this is by writing a PHP socket server.
<?php
// Set time limit to indefinite execution
set_time_limit (0);
// Set the ip and port we will listen on
$address = '192.168.0.100';
$port = 9000;
$max_clients = 10;
// Array that will hold client information
$clients = Array();
// Create a TCP Stream socket
$sock = socket_create(AF_INET, SOCK_STREAM, 0);
// Bind the socket to an address/port
socket_bind($sock, $address, $port) or die('Could not bind to address');
// Start listening for connections
socket_listen($sock);
// Loop continuously
while (true) {
// Setup clients listen socket for reading
$read[0] = $sock;
for ($i = 0; $i < $max_clients; $i++)
{
if ($client[$i]['sock'] != null)
$read[$i + 1] = $client[$i]['sock'] ;
}
// Set up a blocking call to socket_select()
$ready = socket_select($read,null,null,null);
/* if a new connection is being made add it to the client array */
if (in_array($sock, $read)) {
for ($i = 0; $i < $max_clients; $i++)
{
if ($client[$i]['sock'] == null) {
$client[$i]['sock'] = socket_accept($sock);
break;
}
elseif ($i == $max_clients - 1)
print ("too many clients")
}
if (--$ready <= 0)
continue;
} // end if in_array
// If a client is trying to write - handle it now
for ($i = 0; $i < $max_clients; $i++) // for each client
{
if (in_array($client[$i]['sock'] , $read))
{
$input = socket_read($client[$i]['sock'] , 1024);
if ($input == null) {
// Zero length string meaning disconnected
unset($client[$i]);
}
$n = trim($input);
if ($input == 'exit') {
// requested disconnect
socket_close($client[$i]['sock']);
} elseif ($input) {
// strip white spaces and write back to user
$output = ereg_replace("[ \t\n\r]","",$input).chr(0);
socket_write($client[$i]['sock'],$output);
}
} else {
// Close the socket
socket_close($client[$i]['sock']);
unset($client[$i]);
}
}
} // end while
// Close the master sockets
socket_close($sock);
?>
You would execute this by running it through command line and would always have to run for your PHP clients to connect to it. You could then write a PHP client that would connect to the socket.
<?php
$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: www.example.com\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
?>
You would have to use some type of ajax to call with jQuery posting the message to this PHP client.
http://devzone.zend.com/209/writing-socket-servers-in-php/
http://php.net/manual/en/function.fsockopen.php
Better use a node.js server for this. WebSockets aren't cross-browser nowadays (except socket.io for node.js that works perfect)
in short answer, you can't.
the current HTTP/HTML implementation doesn't support the pushstate so the algorithm of your chat app should follow :
A: sent message
B,C,D: do while a new message has been sent get this message.
so the receivers always have to make a new request and check if a new message has been sent. (AJAX Call or something similar )
so always there are a delay between the sent event and the receive event.
which means the data must be saved in something global, like db or file system.
take a look for :
http://today.java.net/article/2010/03/31/html5-server-push-technologies-part-1
You didn't say it had to all be written it PHP :)
Install RabbitMQ, and then use this chat implementation built on top of websockets and RabbitMQ.
Your PHP is pretty much just 'chat room chrome'. It's possible most of your site would fit within the 5 meg limit of offline HTML5 content, and you have a very flexible (and likely more robust than if you did it yourself) chat system.
It even has 20 messages of chat history if you leave the room.
https://github.com/videlalvaro/rabbitmq-chat
If You need to use just PHP, then You can store chat messages in session variables, session could be like object, storing a lot of information.
If You can use jQuery then You could just append paragraph to a div after message has been sent, but then if site is refreshed, messages will be gone.
Or combining, store messages in session and update that with jQuery and ajax.
Try looking into socket libraries like ZeroMQ they allow for instant transport of the message, and are quicker than TCP, and is realtime. Their infrastructure allows for instant data send between points A and B, without the data being stored anywhere first (although you can still choose to).
Here's a tutorial for a chat client in ZeroMQ

Categories