Here's a relatively simple model for an InSim framework for PHP 5. This code only knows about 4 packets so it's far from being complete. Usage example at the bottom.
<?php
php
define('ISP_ISI', 1);
define('ISP_VER', 2);
define('ISP_TINY', 3);
define('ISP_SMALL', 4);
define('ISP_MST', 13);
define('TINY_CLOSE', 2);
interface SocketDriver {
public function open($destination);
public function send($data);
public function receive();
}
class TCPDriver implements SocketDriver {
protected $buffer;
protected $socket;
function open($dest) {
if ($this->socket = stream_socket_client('tcp://'.$dest, $errno, $errstr, 5))
stream_set_blocking($this->socket, FALSE);
else
throw new Exception('no dice');
}
function send($data) {
fwrite($this->socket, $data);
}
function receive() {
if ($data = fread($this->socket, 1024)) {
$this->buffer .= $data;
$packets = array();
while (1) {
if (strlen($this->buffer) < 4)
break;
$size = array_shift(unpack('C', substr($this->buffer, 0, 1)));
if (strlen($this->buffer) >= $size) {
$packet = substr($this->buffer, 0, $size);
$packets[] = $packet;
$this->buffer = substr($this->buffer, $size);
}
else break;
}
return $packets;
}
return FALSE;
}
}
abstract class ISP_Pack {
static $ISP_TINY = array('C', 'C', 'C', 'C');
static $ISP_ISI = array('C', 'C', 'C', 'C', 'v', 'v', 'C', 'C', 'v', 'a16', 'a16');
static $ISP_MST = array('C', 'C', 'C', 'C', 'a64');
}
abstract class ISP_Unpack {
static $ISP_VER = 'CSize/CType/CReqI/CZero/a8Version/a6Product/vInSimVer';
}
class IS_Packet {
static $socketdriver;
static function bindSocketDriver(SocketDriver $driver) {
self::$socketdriver = $driver;
}
function __set($v, $l) { throw new Exception('no such field'); }
function __get($v) { throw new Exception('no such field'); }
function pack() {
$stack = eval('return ISP_Pack::$'.get_class($this).';');
foreach ($this as $item)
$packed .= pack(array_shift($stack), $item);
return $packed;
}
static function unpack($data) {
$type = array_shift(unpack('C', substr($data, 1, 1)));
switch ($type) {
case ISP_TINY:
case ISP_SMALL:
$subtype = array_shift(unpack('C', substr($data, 3, 1)));
# switch ($subtype) ..
break;
case ISP_VER:
$packet = new ISP_VER;
break;
default:
return FALSE;
}
$data = unpack(eval('return ISP_Unpack::$'.get_class($packet).';'), $data);
foreach ($data as $var => $value)
$packet->{$var} = $value;
return $packet;
}
function send() {
self::$socketdriver->send($this->pack());
}
}
class ISP_ISI extends IS_Packet {
var $Size = 44;
var $Type = ISP_ISI;
var $ReqI;
var $Zero;
var $UDPPort;
var $Flags;
var $Sp0;
var $Prefix;
var $Interval;
var $Admin;
var $IName;
}
class ISP_TINY extends IS_Packet {
var $Size = 4;
var $Type = ISP_TINY;
var $ReqI;
var $SubT;
}
class ISP_VER extends IS_Packet {
var $Size;
var $Type;
var $ReqI;
var $Zero;
var $Version;
var $Product;
var $InSimVer;
}
class ISP_MST extends IS_Packet {
var $Size = 68;
var $Type = ISP_MST;
var $ReqI;
var $Zero;
var $Msg;
}
$mySocket = new TCPDriver;
$mySocket->open('127.0.0.1:29999');
IS_Packet::BindSocketDriver($mySocket);
$ISI = new ISP_ISI;
$ISI->ReqI = 1;
$ISI->Admin = 'password';
$ISI->IName = 'PHP 5';
$ISI->send();
while (1) {
if ($packets = $mySocket->Receive()) {
foreach ($packets as $packet) {
$packet = IS_Packet::unpack($packet);
if ($packet instanceof ISP_VER) {
echo 'Connected to LFS ', $packet->Product, ' ', $packet->Version, ' / InSim v', $packet->InSimVer, PHP_EOL;
$MST = new ISP_MST;
$MST->Msg = 'Hello, World!';
$MST->send();
sleep(1);
$InSimClose = new ISP_TINY;
$InSimClose->SubT = TINY_CLOSE;
$InSimClose->send();
exit();
}
}
}
sleep(1);
}
?>