Simple reader for uncompressed TibiaCam files (binary files, up to 60MB).
It’s also example of fast reading binary data from file and handling it as stream.
<?php class BinaryData { /** @var resource */ private $data; /** @var int */ private $length; /** * BinaryData constructor. * @param string $data */ public function __construct($data) { $this->data = fopen('php://memory', 'wb+'); fwrite($this->data, $data); $this->length = ftell($this->data); rewind($this->data); } /** * @return int */ public function getLength() { return $this->length; } /** * @return bool */ public function isEof() { return ftell($this->data) == $this->length; } /** * @param int $length */ public function skip($length) { fseek($this->data, $length, SEEK_CUR); } /** * @return int */ public function getU8() { return unpack('C', fread($this->data, 1))[1]; } /** * @return int */ public function getU16() { return unpack('v', fread($this->data, 2))[1]; } /** * @return int */ public function getU32() { return unpack('V', fread($this->data, 4))[1]; } /** * @return int */ public function getU64() { return unpack('P', fread($this->data, 8))[1]; } /** * @param int $length * @return string */ public function getString($length = -1) { if ($length == -1) { $length = $this->getU16(); } return fread($this->data, $length); } } class NetworkPacket extends BinaryData { /** * 0x01 = packets sent to player * 0x03 = packets received from player * 0x05 = refresh packets for fast cam rewinding */ const TYPE_OUT = 0x01; const TYPE_IN = 0x03; const TYPE_REFRESH = 0x05; /** @var int */ private $type; /** * NetworkPacket constructor. * @param string $data */ public function __construct($data) { parent::__construct($data); $this->type = $this->getU8(); } /** * @return int */ public function getType() { return $this->type; } } class Cam extends BinaryData { /** * Cam constructor. * @param string $filePath path to cam file */ public function __construct($filePath) { parent::__construct(file_get_contents($filePath)); } /** * @return array */ public function readTibiaCamAttributes() { $this->skip(8); // text: TIBIACAM $camVersion = $this->getU8(); $playerId = $this->getU32(); $playerName = $this->getString(); $protocolVersion = $this->getU16(); $timeCreated = $this->getU64(); return [$camVersion, $playerId, $playerName, $protocolVersion, $timeCreated]; } } $fileName = 'nowy.cam.ready'; $cam = new Cam($fileName); $camAttributes = $cam->readTibiaCamAttributes(); var_dump($camAttributes); while (!$cam->isEof()) { $packetTime = $cam->getU64(); var_dump($packetTime); $packet = new NetworkPacket($cam->getString()); var_dump($packet->getType()); var_dump($packet->getLength()); }