Работа с пакетами в PHP
Материал из Perfect World Develop Wiki
Версия от 17:54, 24 мая 2015; DesmondHume (обсуждение | вклад)
PHP
- Код класса
<? // Bei Desmond Hume class ReadPacket { public $data, $pos; function __construct($obj = null) { $this -> data = $obj -> response; } public function ReadBytes($length) { $value = substr($this -> data, $this -> pos, $length); $this -> pos += $length; return $value; } public function ReadUByte() { $value = unpack("C", substr($this -> data, $this -> pos, 1)); $this -> pos++; return $value[1]; } public function ReadFloat() { $value = unpack("f", strrev(substr($this -> data, $this -> pos, 4))); $this -> pos += 4; return $value[1]; } public function ReadUInt32() { $value = unpack("N", substr($this -> data, $this -> pos, 4)); $this -> pos += 4; return $value[1]; } public function ReadUInt16() { $value = unpack("n", substr($this -> data, $this -> pos, 2)); $this -> pos += 2; return $value[1]; } public function ReadOctets() { $length = $this -> ReadCUInt32(); $value = unpack("H*", substr($this -> data, $this -> pos, $length)); $this -> pos += $length; return $value[1]; } public function ReadUString() { $length = $this -> ReadCUInt32(); $value = iconv("UTF-16", "UTF-8", substr($this -> data, $this -> pos, $length)); // LE? $this -> pos += $length; return $value; } public function ReadPacketInfo() { $packetinfo['Opcode'] = $this -> ReadCUInt32(); $packetinfo['Length'] = $this -> ReadCUInt32(); return $packetinfo; } public function Seek($value) { $this -> pos += $value; } public function ReadCUInt32() { $value = unpack("C", substr($this -> data, $this -> pos, 1)); $value = $value[1]; $this -> pos++; switch($value & 0xE0) { case 0xE0: $value = unpack("N", substr($this -> data, $this -> pos, 4)); $value = $value[1]; $this -> pos += 4; break; case 0xC0: $value = unpack("N", substr($this -> data, $this -> pos - 1, 4)); $value = $value[1] & 0x1FFFFFFF; $this -> pos += 3; break; case 0x80: case 0xA0: $value = unpack("n", substr($this -> data, $this -> pos - 1, 2)); $value = $value[1] & 0x3FFF; $this -> pos++; break; } return $value; } } class WritePacket { public $request, $response; public function WriteBytes($value) { $this -> request .= $value; } public function WriteUByte($value) { $this -> request .= pack("C", $value); } public function WriteFloat($value) { $this -> request .= strrev(pack("f", $value)); } public function WriteUInt32($value) { $this -> request .= pack("N", $value); } public function WriteUInt16($value) { $this -> request .= pack("n", $value); } public function WriteOctets($value) { if (ctype_xdigit($value)) $value = pack("H*", $value); $this -> request .= $this -> CUInt(strlen($value)); $this -> request .= $value; } public function WriteUString($value, $coding = "UTF-16LE") { $value = iconv("UTF-8", $coding, $value); $this -> request .= $this -> CUInt(strlen($value)); $this -> request .= $value; } public function Pack($value) { $this -> request = $this -> CUInt($value) . $this -> CUInt(strlen($this -> request)) . $this -> request; } public function Unmarshal() { return $this -> CUInt(strlen($this -> request)) . $this -> request; } public function Send($address, $port) { $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if (socket_connect($socket, $address, $port)) { socket_set_block($socket); $send = socket_send($socket, $this -> request, 131072, 0); $recv = socket_recv($socket, $this -> response, 131072, 0); socket_set_nonblock($socket); socket_close($socket); return true; } else return false; } public function WriteCUInt32($value) { $this -> request .= $this -> CUInt($value); } private function CUInt($value) { if ($value <= 0x7F) return pack("C", $value); else if ($value <= 0x3FFF) return pack("n", ($value | 0x8000)); else if ($value <= 0x1FFFFFFF) return pack("N", ($value | 0xC0000000)); else return pack("C", 0xE0) . pack("N", $value); } } ?>
Пример работы
Для примера рассмотрим получение никнейма персонажа по его ID из сервиса gamedbd через пакет GetRoleBaseArg.
<? include("packet_class.php"); $GetRoleBase = new WritePacket(); $GetRoleBase -> WriteUInt32(-1); // always $GetRoleBase -> WriteUInt32(1024); // userid $GetRoleBase -> Pack(0xBC5); // opcode if (!$GetRoleBase -> Send("localhost", 29400)) // send to gamedbd return; $GetRoleBase_Re = new ReadPacket($GetRoleBase); // reading packet from stream $packetinfo = $GetRoleBase_Re -> ReadPacketInfo(); // read opcode and length $GetRoleBase_Re -> ReadUInt32(); // always $GetRoleBase_Re -> ReadUInt32(); // retcode $GetRoleBase_Re -> ReadUByte(); // version $GetRoleBase_Re -> ReadUInt32(); // id echo $GetRoleBase_Re -> ReadUString(); // show rolename ?>