PHP Websocket server - Handle more frames in socket_recv - php

Hope this wasn't solved here before, but I was really trying to look for answer!
I Have a problem with receiving frames via socket_recv in PHP server. Problem appears when I send more than 1 messages from client in one time (e.g. in cycle). By the stream length it's match frames count but I'm not able to unmask frames correctly and my unmask function return only first frame. I'm using part of php server I found here and for one message it's working properly, but when I receive more messages at time, it don't unmask all.
I tryed to add loop to go thru all frames, but I'm not able to find end of frame and continue to other.
Here is main while of server:
while (true) {
//manage multipal connections
$changed = $clients;
//returns the socket resources in $changed array
socket_select($changed, $null, $null, 0, 10);
//check for new socket
if (in_array($socket, $changed)) {
$socket_new = socket_accept($socket); //accpet new socket
$clients[] = $socket_new; //add socket to client array
$header = socket_read($socket_new, 10240); //read data sent by the socket
perform_handshaking($header, $socket_new, $host, $port); //perform websocket handshake
socket_getpeername($socket_new, $ip); //get ip address of connected socket
$response = mask(json_encode(array('type' => 'system', 'status' => true, "id" => "SRV_CONNECTED", 'message' => $ip . ' connected'))); //prepare json data
send_message($response); //notify all users about new connection
//make room for new socket
$found_socket = array_search($socket, $changed);
unset($changed[$found_socket]);
}
foreach ($changed as $changed_socket) {
while (#socket_recv($changed_socket, $buf, 1024, 0) >= 1) {
$received_text = unmask($buf); //unmask data
$tst_msg = json_decode($received_text, true); //json decode
$response_text = parse_msg($tst_msg, $changed_socket);
break 2; //exit this loop
}
$buf = #socket_read($changed_socket, 10240, PHP_NORMAL_READ);
if ($buf === false) { // check disconnected client
// remove client for $clients array
$found_socket = array_search($changed_socket, $clients);
socket_getpeername($changed_socket, $ip);
unset($clients[$found_socket]);
//notify all users about disconnected connection
$response = mask(json_encode(array('type' => 'system', 'message' => $ip . ' disconnected')));
send_message($response);
}
}
I Need to call parse_msg by count of frames received in #socket_recv which should be returned by unmask function.
And here is unmask function:
function unmask($payload){
$decMessages = Array();
do { // This should be running until all frames are unmasked and added to $decMessages Array
$length = ord($payload[1]) & 127;
if($length == 126) {
$masks = substr($payload, 4, 4);
$data = substr($payload, 8);
$len = (ord($payload[2]) << 8) + ord($payload[3]);
}elseif($length == 127) {
$masks = substr($payload, 10, 4);
$data = substr($payload, 14);
$len = (ord($payload[2]) << 56) + (ord($payload[3]) << 48) +
(ord($payload[4]) << 40) + (ord($payload[5]) << 32) +
(ord($payload[6]) << 24) +(ord($payload[7]) << 16) +
(ord($payload[8]) << 8) + ord($payload[9]);
}else {
$masks = substr($payload, 2, 4);
$data = substr($payload, 6);
$len = $length;
}
$text = '';
for ($i = 0; $i < $len; ++$i) {
$text .= $data[$i] ^ $masks[$i%4];
}
$decMessages[] = $text;
// Here is problem. It doesn't put correct substr to $payload, so it could run again on stream shorted by last message
$payload = substr($payload, $length, strlen($payload));
}while (($len < strlen($data)) and $countert < 10);
return $decMessages;
}
I think my problem is here: $payload = substr($payload, $length, strlen($payload)); Where I'm putting wrongly rest of stream?
So my questions are:
Why #socket_recv return more than one frame
How can i change my unmask function to go thru all frames, not just a first one
I will be extremelly greatfull for any help, because I'm fighting with this more than I should.
Thanks in advance
Klara!

so, I found solution for this. As I thought, problem was multiple frames in one receive. I needed to edit my unmask function to check if there are still frames in stream.
Basically, what I had was right but $length in
$payload = substr($payload, $length, strlen($payload));
was wrong. Instead of $length I used $len + 8, 14 od 6 depend on $length. I'm not sure how to describe why this but I'm sure somebody will. That's all. Now it's working as it should!
Thanks!

Related

How to run php socket server in linux hosting

i have implemented a socket server in localhost
script i used is from http://www.sanwebe.com/2013/05/chat-using-websocket-php-socket
script is
$host = "localhost"; //host
$port = 9099; //port
if(isset($argv[1]))
{
$host = $argv[1];
}
if(isset($argv[2]))
{
$port = $argv[2];
}
$null = NULL; //null var
$ips=array();
//Create TCP/IP sream socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
//reuseable port
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
//bind socket to specified host
socket_bind($socket, 0, $port);
//listen to port
socket_listen($socket);
//create & add listning socket to the list
$clients = array($socket);
$clients_ip=array();
//start endless loop, so that our script doesn't stop
while (true) {
//manage multipal connections
$changed = $clients;
//returns the socket resources in $changed array
socket_select($changed, $null, $null, 0, 10);
//check for new socket
if (in_array($socket, $changed)) {
$socket_new = socket_accept($socket); //accpet new socket
socket_getpeername($socket_new, $ip);
$clients[] = $socket_new; //add socket to client array
$clients_ip[$ip] = $socket_new;
$header = socket_read($socket_new, 1024); //read data sent by the socket
perform_handshaking($header, $socket_new, $host, $port); //perform websocket handshake
//get ip address of connected socket
$ips[]=$ip;
$response = mask(json_encode(array('ip'=>$ip,'type'=>'c', 'message'=>$ip.' connected','ips'=>$ips))); //prepare json data
send_message($response); //notify all users about new connection
//make room for new socket
$found_socket = array_search($socket, $changed);
unset($changed[$found_socket]);
}
//print_r($changed);exit;
if(count($changed)>0)
{
//loop through all connected sockets
foreach ($changed as $changed_socket) {
//check for any incomming data
while(socket_recv($changed_socket, $buf, 1024, 0) >= 1)
{
$received_text = unmask($buf); //unmask data
$tst_msg = json_decode($received_text); //json decode
//$user_name = $tst_msg->name; //sender name
//$user_message = $tst_msg->message; //message text
//$user_color = $tst_msg->color; //color
//prepare data to be sent to clientjson_encode(array('type'=>'usermsg', 'name'=>$user_name, 'message'=>$user_message, 'color'=>$user_color))
$response_text = mask($received_text);
if(isset($tst_msg->type))
{
if($tst_msg->type=="n")
{
#socket_write($clients_ip[$tst_msg->to_ip],$response_text,strlen($response_text));
}
}
//send_message($response_text); //send data
break 2; //exist this loop
}
$buf = #socket_read($changed_socket, 1024, PHP_NORMAL_READ);
if ($buf === false) { // check disconnected client
// remove client for $clients array
$found_socket = array_search($changed_socket, $clients);
socket_getpeername($changed_socket, $ip);
unset($clients[$found_socket]);
if (($key = array_search($ip, $ips)) !== false)
{
unset($ips[$key]);
}
$ips=array_values($ips);
//notify all users about disconnected connection
$response = mask(json_encode(array('ip'=>$ip,'type'=>'d', 'message'=>$ip.' disconnected','ips'=>$ips)));
send_message($response);
}
}
}
}
// close the listening socket
socket_close($sock);
function send_message($msg)
{
global $clients;
foreach($clients as $changed_socket)
{
#socket_write($changed_socket,$msg,strlen($msg));
}
return true;
}
//Unmask incoming framed message
function unmask($text) {
$length = ord($text[1]) & 127;
if($length == 126) {
$masks = substr($text, 4, 4);
$data = substr($text, 8);
}
elseif($length == 127) {
$masks = substr($text, 10, 4);
$data = substr($text, 14);
}
else {
$masks = substr($text, 2, 4);
$data = substr($text, 6);
}
$text = "";
for ($i = 0; $i < strlen($data); ++$i) {
$text .= $data[$i] ^ $masks[$i%4];
}
return $text;
}
//Encode message for transfer to client.
function mask($text)
{
$b1 = 0x80 | (0x1 & 0x0f);
$length = strlen($text);
if($length <= 125)
$header = pack('CC', $b1, $length);
elseif($length > 125 && $length < 65536)
$header = pack('CCn', $b1, 126, $length);
elseif($length >= 65536)
$header = pack('CCNN', $b1, 127, $length);
return $header.$text;
}
//handshake new client.
function perform_handshaking($receved_header,$client_conn, $host, $port)
{
$headers = array();
$lines = preg_split("/\r\n/", $receved_header);
foreach($lines as $line)
{
$line = chop($line);
if(preg_match('/\A(\S+): (.*)\z/', $line, $matches))
{
$headers[$matches[1]] = $matches[2];
}
}
$secKey = $headers['Sec-WebSocket-Key'];
$secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
//hand shaking header
$upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
"Upgrade: websocket\r\n" .
"Connection: Upgrade\r\n" .
"WebSocket-Origin: $host\r\n" .
"WebSocket-Location: ws://$host:$port/demo/shout.php\r\n".
"Sec-WebSocket-Accept:$secAccept\r\n\r\n";
socket_write($client_conn,$upgrade,strlen($upgrade));
}
i run this program in xampp shell like
php -q path-to-server\server.php
i have a server with shell support
But when i run script
php -q path-to-server\server.php
it works but when shell is closed server will close automatically
so how to run this server continuously with out automatically closing?
i have a linux hosting package
Use this code,
php -f server.php
if you want to run continusely in banground you can use nohub
nohup php server.php &
if want to kill the process you use kill
kill processid
you can run in terminal
php filename.php
I'm guessing you are connecting to the server by ssh?
The server session is ending and all open proccesses are killed that is why your server instance is ending, you are running it from a non-privileged user.
So the way I use is to install screen on the remote server and use that.
https://www.gnu.org/software/screen/manual/screen.html
Or it looks like you might be running a windows server. If this is the case I would recomend using a Linux server as windows makes this a little harder. You will have to run your server instance as a system proccess.
you should run this command as a background proccess like
nohup php -f myBind.php > /dev/null &
Also you can put a simple sccript to crontab for checking your bind.php is up or not if its not run it again.

Cannot get required headers from some IPs and ports to parse song title using ShoutCast protocol

I'm trying to extract song title from live mp3 streams using SC protocol. The php script works fine with some IPs and ports, however with some IPs and ports I cannot get required headers from the response to determine the meta-block frequency, therefore I cannot find the location of the song title in the stream. Here's my code:
<?php
while(true)
{
//close warning messages (re-open for debugging)
error_reporting(E_ERROR | E_PARSE);
//create and connect socket with the parameters entered by the user
$sock = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
echo "Establishing connection to the given adress...\n";
$fp = fsockopen($argv[1], $argv[2], $errno, $errstr, 10);
if($fp)
{
echo "Connection established.\n";
$result = socket_connect($sock, $argv[1], $argv[2]);
//prepare request
$request = "GET / HTTP/1.1\r\n";
$request .= "Icy-MetaData: 1\r\n\r\n";
//send request
socket_write($sock,$request,strlen($request));
//set sentinel boolean value's initial value
$headers = true;
//put the segment to be parsed into a string variable
$l = socket_read($sock,2048);
$meta = "";
$streamurl = "";
$checkContentType = false;
//Parsing metadata frequency and streamurl from response's headers.
foreach(preg_split("/((\r?\n)|(\r\n?))/", $l) as $line)
{
if(!(strpos($line, "metaint:") === false))
{
$meta = $line;
}
if(!(strpos($line, "icy-url:") === false))
{
$streamurl = $line;
}
if(!strpos($line, "audio/mpeg") === false)
{
$checkContentType = true;
}
}
echo $l;
//Checking if the content of the stream is mpeg or not
if($checkContentType)
{
$pos = strpos($meta, ":");
$interval = intval(substr($meta,$pos+1));
$pos = strpos($streamurl, ":");
$streamurl = substr($streamurl, $pos+1);
$flag = false;
//initialize bytecount to 0
$bytecount = 0;
//Extracting song title using SC protocol
while($headers)
{
$l = socket_read($sock,PHP_NORMAL_READ);
$bytecount++;
if($bytecount == $interval )
{
$headers = false;
$flag = true;
}
if($flag)
{
$len = ord($l);
}
}
//Determining length variable
$len = $len * 16;
$string = socket_read($sock,$len);
$pos2 = strpos($string, "'") + 1;
$pos3 = strpos($string, ";",$pos2) -1;
$songtitle = substr($string, $pos2, ($pos3-$pos2));
//Formatting the log entry
$finalstr = "[".date("c")."]"."[".$streamurl."]".$songtitle."\n";
echo "logged".$finalstr;
//finalize connection
socket_close($sock);
//Writing the requested info to a log file
file_put_contents("log.txt", $finalstr,FILE_APPEND | LOCK_EX);
//waiting 5 minutes
echo "Logging next entry in five minutes. \n";
sleep(300);
}
else
{
echo "Content of the stream is not suitable.\n";
exit;
}
}
else
{
echo "Unable to connect to the given ip and port.\n Exiting...\n";
socket_close($sock);
exit;
}
}
?>
I've never tried to access shoutcast programatically but I've run streaming audio servers in the past. There are actually two different flavours of shoutcast server and I would guess your program is trying to talk to one and these broken servers are the other type.
From the post READING SHOUTCAST METADATA FROM A STREAM:
Turns out that SHOUTcast and Icecast (two of the most popular server
applications for streaming radio) are supposed to be compatible, but
the response message from each server is slightly different.
Full details about the shoutcast protocol: Shoutcast Metadata Protocol

Speed of PHP UDP scraper is incredibly slow, how to improve?

I am working on a little project of mine and have built a UDP scraper that uses sockets to return data about a specific sha1 hash.
It works but is incredibly slow and wondered if any one knows how I could speed it up or improve the existing code.
The code is below;
// SCRAPE UDP
private function scrapeUDP($tracker, $hash) {
// GET TRACKER DETAILS
preg_match('%udp://([^:/]*)(?::([0-9]*))?(?:/)?%i', $tracker, $info);
// GENERATE TRANSACTION ID
$transID = mt_rand(0, 65535);
// PACKED TRANSACTION ID
$packedTransID = pack('N', $transID);
// ATTEMPT TO CREATE A SOCKET
if(!$socket = #fsockopen('udp://' . $info[1], $info[2], $errno, $errstr, 2)) {
return;
}
// SET STREAM TIMEOUT
stream_set_timeout($socket, 2);
// CONNECTION ID
$connID = "\x00\x00\x04\x17\x27\x10\x19\x80";
// BUILD CONNECTION REQUEST PACKET
$packet = $connID . pack('N', 0) . $packedTransID;
// SEND PACKET
fwrite($socket, $packet);
// CONNECTION RESPONSE
$response = fread($socket, 16);
// CHECK CONNECTION RESPONSE LENGTH
if(strlen($response) < 16) {
return;
}
// UNPACK CONNECTION RESPONSE
$returnData = unpack('Naction/NtransID', $response);
// CHECK CONNECTION RESPONSE DATA
if($returnData['action'] != 0 || $returnData['transID'] != $transID) {
return;
}
// GET CONNECTION ID
$connID = substr($response, 8, 8);
// BUILD SCRAPE PACKET
$packet = $connID . pack('N', 2) . $packedTransID . $hash;
// SEND SCRAPE PACKET
fwrite($socket, $packet);
// SCRAPE RESPONSE
$response = fread($socket, 20);
// CHECK SCRAPE RESPONSE LENGTH
if(strlen($response) < 20) {
return;
}
// UNPACK SCRAPE RESPONSE
$returnData = unpack('Naction/NtransID', $response);
// CHECK SCRAPE RESPONSE DATA
if($returnData['action'] != 2 || $returnData['transID'] != $transID) {
return;
}
// UNPACK SCRAPE INFORMATION
$returnData = unpack('Nseeders/Ncompleted/Nleechers', substr($response, 8, 12));
// RETURN TRACKER INFORMATION
return array('seeders' => $returnData['seeders'], 'leechers' => $returnData['leechers'],);
}
It is my first time I have ever created anything to do with sockets or UDP so forgive me if it is a mess!
Thanks...
You have to make parallel request using socket_select() and non-blocking sockets or forks, because you are spending a lot of time in waiting for the response. Additionally, it may be better to use low-level functions like socket_read() or similar to control connection and data transmission better.

How can Javascript client connect to PHp socket Server?

Hi I have a running socket server written with PHP.
The server is listening for connections.. any idea how my client(written in javascript) is going to connect to the server and send data to it?
PS: I only know how to connect a php client to the socket server but unsure how to connect a javascript client.
Thanks all for your time.
I use standard WebSocket API for client.
And core PHP socket for server side.
know, send and received data use a header on the browser with websocket. But the code PHP socket, send and received without header and just send plain data.
So we need to simulate header on the socketing server side.
For learning and know how do it, I write this clear sample code, With this code you can send a phrase to server and receive reverse phrase that in client.
server.php
<?php
//Code by: Nabi KAZ <www.nabi.ir>
// set some variables
$host = "127.0.0.1";
$port = 5353;
// don't timeout!
set_time_limit(0);
// create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0)or die("Could not create socket\n");
// bind socket to port
$result = socket_bind($socket, $host, $port)or die("Could not bind to socket\n");
// start listening for connections
$result = socket_listen($socket, 20)or die("Could not set up socket listener\n");
$flag_handshake = false;
$client = null;
do {
if (!$client) {
// accept incoming connections
// client another socket to handle communication
$client = socket_accept($socket)or die("Could not accept incoming connection\n");
}
$bytes = #socket_recv($client, $data, 2048, 0);
if ($flag_handshake == false) {
if ((int)$bytes == 0)
continue;
//print("Handshaking headers from client: ".$data."\n");
if (handshake($client, $data, $socket)) {
$flag_handshake = true;
}
}
elseif($flag_handshake == true) {
if ($data != "") {
$decoded_data = unmask($data);
print("< ".$decoded_data."\n");
$response = strrev($decoded_data);
socket_write($client, encode($response));
print("> ".$response."\n");
socket_close($client);
$client = null;
$flag_handshake = false;
}
}
} while (true);
// close sockets
socket_close($client);
socket_close($socket);
function handshake($client, $headers, $socket) {
if (preg_match("/Sec-WebSocket-Version: (.*)\r\n/", $headers, $match))
$version = $match[1];
else {
print("The client doesn't support WebSocket");
return false;
}
if ($version == 13) {
// Extract header variables
if (preg_match("/GET (.*) HTTP/", $headers, $match))
$root = $match[1];
if (preg_match("/Host: (.*)\r\n/", $headers, $match))
$host = $match[1];
if (preg_match("/Origin: (.*)\r\n/", $headers, $match))
$origin = $match[1];
if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $headers, $match))
$key = $match[1];
$acceptKey = $key.'258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
$acceptKey = base64_encode(sha1($acceptKey, true));
$upgrade = "HTTP/1.1 101 Switching Protocols\r\n".
"Upgrade: websocket\r\n".
"Connection: Upgrade\r\n".
"Sec-WebSocket-Accept: $acceptKey".
"\r\n\r\n";
socket_write($client, $upgrade);
return true;
} else {
print("WebSocket version 13 required (the client supports version {$version})");
return false;
}
}
function unmask($payload) {
$length = ord($payload[1]) & 127;
if ($length == 126) {
$masks = substr($payload, 4, 4);
$data = substr($payload, 8);
}
elseif($length == 127) {
$masks = substr($payload, 10, 4);
$data = substr($payload, 14);
}
else {
$masks = substr($payload, 2, 4);
$data = substr($payload, 6);
}
$text = '';
for ($i = 0; $i < strlen($data); ++$i) {
$text .= $data[$i] ^ $masks[$i % 4];
}
return $text;
}
function encode($text) {
// 0x1 text frame (FIN + opcode)
$b1 = 0x80 | (0x1 & 0x0f);
$length = strlen($text);
if ($length <= 125)
$header = pack('CC', $b1, $length);
elseif($length > 125 && $length < 65536)$header = pack('CCS', $b1, 126, $length);
elseif($length >= 65536)
$header = pack('CCN', $b1, 127, $length);
return $header.$text;
}
client.htm
<html>
<script>
//Code by: Nabi KAZ <www.nabi.ir>
var socket = new WebSocket('ws://localhost:5353');
// Open the socket
socket.onopen = function(event) {
var msg = 'I am the client.';
console.log('> ' + msg);
// Send an initial message
socket.send(msg);
// Listen for messages
socket.onmessage = function(event) {
console.log('< ' + event.data);
};
// Listen for socket closes
socket.onclose = function(event) {
console.log('Client notified socket has closed', event);
};
// To close the socket....
//socket.close()
};
</script>
<body>
<p>Please check the console log of your browser.</p>
</body>
</html>
Manual: first run php server.php on CLI and then open http://localhost/client.htm on browser.
You can see result:
http://localhost/client.htm
> I am the client.
< .tneilc eht ma I
php server.php
< I am the client.
> .tneilc eht ma I
Be careful it's just a sample code for test send and receive data, And it is not useful for executive work.
I suggest you use these projects:
https://github.com/ghedipunk/PHP-Websockets
https://github.com/esromneb/phpwebsocket
https://github.com/acbrandao/PHP/tree/master/ws
https://github.com/srchea/PHP-Push-WebSocket/
http://socketo.me/
And also I suggest you these articles for more details:
http://www.abrandao.com/2013/06/websockets-html5-php/
http://cuelogic.com/blog/php-and-html5-websocket-server-and-client-communication/
http://srchea.com/build-a-real-time-application-using-html5-websockets
Answering an old question in case people find it as I did via Google.
Nowadays nearly all contemporary browsers support the WebSocket Javascript API. Via WS it's possible for client JS in the browser to open full duplex sockets to severs written in PHP or other languages. The server must implement the WS protocol, but there are WS libraries now for PHP, Java, and other languages.
At this moment of writing, WS implementations still seem like a bit of a moving target, but, I'm currently working with WS/JS browser clients communicating with a WS/Java server and it does seem to be working.
Suggest Googling for WS implementations in your server language of choice.
Hope this helps!
I'm not aware of anything that provides arbitrary socket capabilities for JS. There is limited support for Web Sockets (which I think will require you to modify the server to conform to the space). Failing that, simple XHR might meet your needs (which would require that you modify the server to act as a web service). If the service runs on a different origin to the page, then you will need to use CORS or use a work around such as JSONP.
Try this:
http://code.google.com/p/phpwebsocket/
Shortly saying - you can't do that - it would be a security breach to let client side code open socket connections.
However, you could simulate that - send your data to another PHP page as an AJAX request, then make that PHP page communicate through the socket.
Update 2017:
In the mean time, websockets became a thing. Please note that the websocket protocol is a different thing than generic networking sockets

TCP server (php)

I have a gps simulator, which sends continuous location data (nmea strings) through tcpip to 192.168.0.178:2323. How do I get that data using tcp socket and write to DB (php & mysql)?
Thanks!
This is a loaded question. First you need to read the data. Then you have to put some structure to the data for it to be usable. It doesn't do you much good to just dump lat-lon to a database. You probably want to save it as a waypoint or part of a track etc.
So I have no answer to the DB question. Here is part of the PHP program I use to read GPS data off my phone connected to a CradlePoint router. It's modified from GoogleNav code.
function read_gps() {
set_time_limit(5);
$fp = fsockopen ("192.168.0.1", 8080, $errno, $errstr, 30);
if (!$fp) {
die ("$errstr ($errno)");
}
$point=false;
$status="";
$fix=0;
while (!$point) {
$string=#fgets($fp, 4096);
switch (substr($string,0,6)) {
case "\$GPRMC" :
list($sentence, $time, $status, $latitude, $NS, $longitude, $EW, $speed, $course, $date, $magvar, $magvarEW)= explode(",", trim($string));
$latd=convdec($latitude, $NS);
$lond=convdec($longitude, $EW);
break;
case "\$GPGGA" :
list($sentence, $time, $latitude, $NS, $longitude, $EW, $fix, $nbsat, $HDOP, $altitude,,,,,)= explode(",", trim($string));
$latd=convdec($latitude, $NS);
$lond=convdec($longitude, $EW);
break;
default :
break;
}
if ($status=="A" and $fix == 1){
$point=true;
}
}
...
?>
Start here: PHP Sockets
One of the user comments gives a helpful sample implementation of a TFTP client
<?php
function tftp_fetch($host, $filename)
{
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
// create the request packet
$packet = chr(0) . chr(1) . $filename . chr(0) . 'octet' . chr(0);
// UDP is connectionless, so we just send on it.
socket_sendto($socket, $packet, strlen($packet), 0x100, $host, 69);
$buffer = '';
$port = '';
$ret = '';
do
{
// $buffer and $port both come back with information for the ack
// 516 = 4 bytes for the header + 512 bytes of data
socket_recvfrom($socket, $buffer, 516, 0, $host, $port);
// add the block number from the data packet to the ack packet
$packet = chr(0) . chr(4) . substr($buffer, 2, 2);
// send ack
socket_sendto($socket, $packet, strlen($packet), 0, $host, $port);
// append the data to the return variable
// for large files this function should take a file handle as an arg
$ret .= substr($buffer, 4);
}
while(strlen($buffer) == 516); // the first non-full packet is the last.
return $ret;
}
?>

Categories