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; public static function new() { $ffi = OpenSSL::getFFI(); $bio = $ffi->BIO_new($ffi->BIO_s_mem()); return new BIO($ffi, $bio); } public static function buffer(string $data) { $ffi = OpenSSL::getFFI(); $bio = $ffi->BIO_new_mem_buf($data, strlen($data)); return new BIO($ffi, $bio); } public static function open($fileName, $flags) { $ffi = OpenSSL::getFFI(); $bio = $ffi->BIO_new_file($fileName, $flags); return new BIO($ffi, $bio); } protected function freeObject() { $this->ffi->BIO_free($this->cObj); } 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; } function getType(): int { return $this->ffi->BIO_method_type($this->cObj); } 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); } 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; } function reset() { $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"); } 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"); } } function eof(): bool { return (int)$this->ctrl(self::CTRL_EOF, 0, null) === 1; } function ctrl($prop, ?int $larg, $parg) { return $this->ffi->BIO_ctrl($this->cObj, $prop, $larg, $parg); } }