Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.
<?php
>
/** * This file is part of FPDI * * @package setasign\Fpdi
< * @copyright Copyright (c) 2019 Setasign - Jan Slabon (https://www.setasign.com)
> * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
* @license http://opensource.org/licenses/mit-license The MIT License */ namespace setasign\Fpdi\PdfParser; /** * A stream reader class
< * < * @package setasign\Fpdi\PdfParser
*/ class StreamReader { /** * Creates a stream reader instance by a string value. * * @param string $content * @param int $maxMemory * @return StreamReader */ public static function createByString($content, $maxMemory = 2097152) { $h = \fopen('php://temp/maxmemory:' . ((int) $maxMemory), 'r+b'); \fwrite($h, $content); \rewind($h); return new self($h, true); } /** * Creates a stream reader instance by a filename. * * @param string $filename * @return StreamReader */ public static function createByFile($filename) { $h = \fopen($filename, 'rb'); return new self($h, true); } /** * Defines whether the stream should be closed when the stream reader instance is deconstructed or not. * * @var bool */ protected $closeStream; /** * The stream resource. * * @var resource */ protected $stream; /** * The byte-offset position in the stream. * * @var int */ protected $position; /** * The byte-offset position in the buffer. * * @var int */ protected $offset; /** * The buffer length. * * @var int */ protected $bufferLength; /** * The total length of the stream. * * @var int */ protected $totalLength; /** * The buffer. * * @var string */ protected $buffer; /** * StreamReader constructor. * * @param resource $stream * @param bool $closeStream Defines whether to close the stream resource if the instance is destructed or not. */ public function __construct($stream, $closeStream = false) { if (!\is_resource($stream)) { throw new \InvalidArgumentException( 'No stream given.' ); } $metaData = \stream_get_meta_data($stream); if (!$metaData['seekable']) { throw new \InvalidArgumentException( 'Given stream is not seekable!' ); } $this->stream = $stream; $this->closeStream = $closeStream; $this->reset(); } /** * The destructor. */ public function __destruct() { $this->cleanUp(); } /** * Closes the file handle. */ public function cleanUp() { if ($this->closeStream && is_resource($this->stream)) { \fclose($this->stream); } } /** * Returns the byte length of the buffer. * * @param bool $atOffset * @return int */ public function getBufferLength($atOffset = false) { if ($atOffset === false) { return $this->bufferLength; } return $this->bufferLength - $this->offset; } /** * Get the current position in the stream. * * @return int */ public function getPosition() { return $this->position; } /** * Returns the current buffer. * * @param bool $atOffset * @return string */ public function getBuffer($atOffset = true) { if ($atOffset === false) { return $this->buffer; } $string = \substr($this->buffer, $this->offset); return (string) $string; } /** * Gets a byte at a specific position in the buffer. * * If the position is invalid the method will return false. * * If the $position parameter is set to null the value of $this->offset will be used. * * @param int|null $position * @return string|bool */ public function getByte($position = null) { $position = (int) ($position !== null ? $position : $this->offset);
< if ($position >= $this->bufferLength && < (!$this->increaseLength() || $position >= $this->bufferLength)
> if ( > $position >= $this->bufferLength > && (!$this->increaseLength() || $position >= $this->bufferLength)
) { return false; } return $this->buffer[$position]; } /** * Returns a byte at a specific position, and set the offset to the next byte position. * * If the position is invalid the method will return false. * * If the $position parameter is set to null the value of $this->offset will be used. * * @param int|null $position * @return string|bool */ public function readByte($position = null) { if ($position !== null) { $position = (int) $position; // check if needed bytes are available in the current buffer if (!($position >= $this->position && $position < $this->position + $this->bufferLength)) { $this->reset($position); $offset = $this->offset; } else { $offset = $position - $this->position; } } else { $offset = $this->offset; }
< if ($offset >= $this->bufferLength && < ((!$this->increaseLength()) || $offset >= $this->bufferLength)
> if ( > $offset >= $this->bufferLength > && ((!$this->increaseLength()) || $offset >= $this->bufferLength)
) { return false; } $this->offset = $offset + 1; return $this->buffer[$offset]; } /** * Read bytes from the current or a specific offset position and set the internal pointer to the next byte. * * If the position is invalid the method will return false. * * If the $position parameter is set to null the value of $this->offset will be used. * * @param int $length * @param int|null $position
< * @return string
> * @return string|false
*/ public function readBytes($length, $position = null) { $length = (int) $length; if ($position !== null) { // check if needed bytes are available in the current buffer if (!($position >= $this->position && $position < $this->position + $this->bufferLength)) { $this->reset($position, $length); $offset = $this->offset; } else { $offset = $position - $this->position; } } else { $offset = $this->offset; }
< if (($offset + $length) > $this->bufferLength && < ((!$this->increaseLength($length)) || ($offset + $length) > $this->bufferLength)
> if ( > ($offset + $length) > $this->bufferLength > && ((!$this->increaseLength($length)) || ($offset + $length) > $this->bufferLength)
) { return false; } $bytes = \substr($this->buffer, $offset, $length); $this->offset = $offset + $length; return $bytes; } /** * Read a line from the current position. * * @param int $length * @return string|bool */ public function readLine($length = 1024) { if ($this->ensureContent() === false) { return false; } $line = ''; while ($this->ensureContent()) { $char = $this->readByte(); if ($char === "\n") { break; } if ($char === "\r") { if ($this->getByte() === "\n") { $this->addOffset(1); } break; } $line .= $char; if (\strlen($line) >= $length) { break; } } return $line; } /** * Set the offset position in the current buffer. * * @param int $offset */ public function setOffset($offset) { if ($offset > $this->bufferLength || $offset < 0) { throw new \OutOfRangeException( \sprintf('Offset (%s) out of range (length: %s)', $offset, $this->bufferLength) ); } $this->offset = (int) $offset; } /** * Returns the current offset in the current buffer. * * @return int */ public function getOffset() { return $this->offset; } /** * Add an offset to the current offset. * * @param int $offset */ public function addOffset($offset) { $this->setOffset($this->offset + $offset); } /** * Make sure that there is at least one character beyond the current offset in the buffer. * * @return bool */ public function ensureContent() { while ($this->offset >= $this->bufferLength) { if (!$this->increaseLength()) { return false; } } return true; } /** * Returns the stream. * * @return resource */ public function getStream() { return $this->stream; } /** * Gets the total available length. * * @return int */ public function getTotalLength() { if ($this->totalLength === null) { $stat = \fstat($this->stream); $this->totalLength = $stat['size']; } return $this->totalLength; } /** * Resets the buffer to a position and re-read the buffer with the given length. * * If the $pos parameter is negative the start buffer position will be the $pos'th position from * the end of the file. * * If the $pos parameter is negative and the absolute value is bigger then the totalLength of * the file $pos will set to zero. * * @param int|null $pos Start position of the new buffer * @param int $length Length of the new buffer. Mustn't be negative */ public function reset($pos = 0, $length = 200) { if ($pos === null) { $pos = $this->position + $this->offset; } elseif ($pos < 0) { $pos = \max(0, $this->getTotalLength() + $pos); } \fseek($this->stream, $pos); $this->position = $pos; $this->buffer = $length > 0 ? \fread($this->stream, $length) : ''; $this->bufferLength = \strlen($this->buffer); $this->offset = 0; // If a stream wrapper is in use it is possible that // length values > 8096 will be ignored, so use the // increaseLength()-method to correct that behavior if ($this->bufferLength < $length && $this->increaseLength($length - $this->bufferLength)) { // increaseLength parameter is $minLength, so cut to have only the required bytes in the buffer $this->buffer = \substr($this->buffer, 0, $length); $this->bufferLength = \strlen($this->buffer); } } /** * Ensures bytes in the buffer with a specific length and location in the file. * * @param int $pos * @param int $length * @see reset() */ public function ensure($pos, $length) {
< if ($pos >= $this->position
> if ( > $pos >= $this->position
&& $pos < ($this->position + $this->bufferLength) && ($this->position + $this->bufferLength) >= ($pos + $length) ) { $this->offset = $pos - $this->position; } else { $this->reset($pos, $length); } } /** * Forcefully read more data into the buffer. * * @param int $minLength * @return bool Returns false if the stream reaches the end */ public function increaseLength($minLength = 100) { $length = \max($minLength, 100); if (\feof($this->stream) || $this->getTotalLength() === $this->position + $this->bufferLength) { return false; } $newLength = $this->bufferLength + $length; do { $this->buffer .= \fread($this->stream, $newLength - $this->bufferLength); $this->bufferLength = \strlen($this->buffer); } while (($this->bufferLength !== $newLength) && !\feof($this->stream)); return true; } }