bin filter */ const TYPE_BER = (18 | 0x0200); /** * (half a) BIO pair */ const TYPE_BIO = (19 | 0x0400); /** * filter */ const TYPE_LINEBUFFER = (20 | 0x0200); const TYPE_DGRAM = (21 | 0x0400 | 0x0100); /** * filter */ const TYPE_ASN1 = (22 | 0x0200); /** * filter */ const TYPE_COMP = (23 | 0x0200); /** * socket, fd, connect or accept */ const TYPE_DESCRIPTOR = 0x0100; const TYPE_FILTER = 0x0200; const TYPE_SOURCE_SINK = 0x0400; /** * BIO_TYPE_START is the first user-allocated BIO type. No pre-defined type, * flag bits aside, may exceed this value. */ const TYPE_START = 128; const FLAG_READ = 0x01; const FLAG_WRITE = 0x02; const FLAG_IO_SPECIAL = 0x04; const FLAG_RWS = self::FLAG_READ | self::FLAG_WRITE | self::FLAG_IO_SPECIAL; const FLAG_SHOULD_RETRY = 0x08; /** * Create new memory based BIO * * @return BIO */ public static function new(): BIO { $ffi = OpenSSL::getFFI(); $bio = $ffi->BIO_new($ffi->BIO_s_mem()); return new BIO($ffi, $bio); } /** * Create new memory based BIO pre-filled with data * * @param string $data * @return BIO */ public static function buffer(string $data): BIO { $ffi = OpenSSL::getFFI(); $bio = $ffi->BIO_new_mem_buf($data, strlen($data)); return new BIO($ffi, $bio); } /** * Create new file BIO with given mode * * @param string $fileName which file to open * @param string $mode mode to open file with see fopen(3) * @return BIO * @see fopen */ public static function open(string $fileName, string $mode): BIO { $ffi = OpenSSL::getFFI(); $bio = $ffi->BIO_new_file($fileName, $mode); return new BIO($ffi, $bio); } /** * @inheritDoc */ protected function freeObject() { $this->ffi->BIO_free($this->cObj); } /** * Write given data to BIO, returns amount of bytes written * * @param string $data * @return int */ public function write(string $data): int { $len = $this->ffi->BIO_write($this->cObj, $data, strlen($data)); if ($len === -2) { throw new RuntimeException("Can't wrote to this BIO"); } if ($len === 0 || $len === -1) { if ($this->cObj->flags & self::FLAG_SHOULD_RETRY) { return $len; } throw new RuntimeException("Error occured while reading BIO"); } return $len; } /** * Get type of BIO, indicating if this is e.g. a file see BIO::TYPE_* constants * * @return int */ public function getType(): int { return $this->ffi->BIO_method_type($this->cObj); } /** * Read from BIO * * @param int $chunkSize max amount of bytes to read in this operation * @return string */ public function read(int $chunkSize = 4096): string { $data = OpenSSL\C\Memory::new($chunkSize); $len = $this->ffi->BIO_read($this->cObj, $data->get(), $chunkSize); if ($len === -2) { throw new RuntimeException("Can't read from this BIO"); } if ($len === 0 || $len === -1) { if ($this->cObj->flags & self::FLAG_SHOULD_RETRY) { return ""; } throw new RuntimeException("Error occured while reading BIO"); } return $data->string($len); } /** * Get location in file pointer, this only works with file BIO's * * @return int */ public function tell() { if (($this->getType() & self::TYPE_FILE) !== self::TYPE_FILE) { throw new RuntimeException("Can't tell on non-file BIO"); } $pos = (int)$this->ctrl(self::C_FILE_TELL, 0, null); if ($pos === -1) { throw new RuntimeException("Failed to tell position in BIO"); } return $pos; } /** * Reset position in BIO */ public function reset(): void { $res = (int)$this->ctrl(self::CTRL_RESET, 0, null); if (($this->getType() & self::TYPE_FILE) === self::TYPE_FILE && $res === 0) { return; } if ($res > 0) { return; } throw new RuntimeException("Failed to reset BIO"); } /** * Seek in BIO, only works on file BIO's * * @param int $offset */ public function seek(int $offset) { if (($this->getType() & self::TYPE_FILE) !== self::TYPE_FILE) { throw new RuntimeException("Can't seek in non-file BIO"); } $pos = (int)$this->ctrl(self::C_FILE_SEEK, $offset, null); if ($pos === -1) { throw new RuntimeException("Failed seeking in BIO"); } } /** * returns true if we're at EOF of this BIO * * @return bool */ public function eof(): bool { return (int)$this->ctrl(self::CTRL_EOF, 0, null) === 1; } /** * Send control command to BIO * * @param int $prop * @param int $larg * @param mixed $parg * @return mixed */ public function ctrl(int $prop, int $larg = 0, $parg = null) { return $this->ffi->BIO_ctrl($this->cObj, $prop, $larg, $parg); } }