Your IP : 216.73.216.81


Current Path : /srv/web/sites/trentinoplant.it/httpdocs/vendor1/phpgt/dom/src/
Upload File :
Current File : /srv/web/sites/trentinoplant.it/httpdocs/vendor1/phpgt/dom/src/DocumentStream.php

<?php

namespace Gt\Dom;

use Gt\Dom\Exception\DocumentStreamIsClosedException;
use Gt\Dom\Exception\DocumentStreamNotWritableException;
use Gt\Dom\Exception\DocumentStreamSeekFailureException;
use Gt\Dom\Exception\WriteOnNonHTMLDocumentException;
use RuntimeException;
use TypeError;

trait DocumentStream {
	/** @var ?resource */
	protected $stream;
	protected int $streamBytesFilled;

	/**
	 * Closes the stream and any underlying resources.
	 */
	public function close():void {
		$this->stream = null;
	}

	/**
	 * Separates any underlying resources from the stream.
	 *
	 * After the stream has been detached, the stream is in an unusable state.
	 *
	 * @return resource|null Underlying PHP stream, if any
	 */
	public function detach() {
		$this->fillStream();
		$stream = $this->stream;
		$this->stream = null;
		return $stream;
	}

	/**
	 * Get the size of the stream if known.
	 */
	public function getSize():?int {
		$this->fillStream();
		return $this->streamBytesFilled;
	}

	/**
	 * Returns the current position of the file read/write pointer
	 */
	public function tell():int {
		return ftell($this->stream);
	}

	/**
	 * Returns true if the stream is at the end of the stream.
	 */
	public function eof():bool {
		$tell = $this->tell();
		$this->fillStream();
		$this->seek($tell);
		return feof($this->stream) || $tell >= $this->streamBytesFilled;
	}

	/**
	 * Returns whether or not the stream is seekable.
	 */
	public function isSeekable():bool {
		$seekable = $this->getMetadata("seekable");
		return $seekable ?? false;
	}

	/**
	 * Seek to a position in the stream.
	 *
	 * @link http://www.php.net/manual/en/function.fseek.php
	 * @param int $offset Stream offset
	 * @param int $whence Specifies how the cursor position will be calculated
	 *     based on the seek offset. Valid values are identical to the built-in
	 *     PHP $whence values for `fseek()`.  SEEK_SET: Set position equal to
	 *     offset bytes SEEK_CUR: Set position to current location plus offset
	 *     SEEK_END: Set position to end-of-stream plus offset.
	 * @throws RuntimeException on failure.
	 */
	public function seek($offset, $whence = SEEK_SET):void {
		$result = null;
		$this->fillStream();

		try {
			$result = fseek($this->stream, $offset, $whence);
		}
		finally {
			if($result === -1) {
				throw new DocumentStreamSeekFailureException("Error seeking Document Stream");
			}
		}
	}

	/**
	 * Seek to the beginning of the stream.
	 *
	 * If the stream is not seekable, this method will raise an exception;
	 * otherwise, it will perform a seek(0).
	 *
	 * @throws RuntimeException on failure.
	 * @link http://www.php.net/manual/en/function.fseek.php
	 * @see seek()
	 */
	public function rewind():void {
		$this->fillStream();
		$this->seek(0);
	}

	/**
	 * Returns whether or not the stream is writable.
	 *
	 * @return bool
	 */
	public function isWritable():bool {
		if(!isset($this->stream)) {
			return false;
		}

		$mode = $this->getMetadata("mode");
		$writable = false;

		if(strstr($mode, "w") || strstr($mode, "+") || strstr($mode, "a")) {
			$writable = true;
		}

		return $writable;
	}

	/**
	 * The Document.write() method writes a string of text to a document
	 * stream opened by document.open().
	 *
	 * Note: Because document.write() writes to the document stream, calling
	 * document.write() on a closed (loaded) document automatically calls
	 * document.open(), which will clear the document.
	 *
	 * @param string $string The string that is to be written.
	 * @return int Returns the number of bytes written to the stream.
	 * @throws RuntimeException on failure.
	 */
	public function write($string):int {
		if(!$this->isWritable() || !$this instanceof HTMLDocument) {
			throw new DocumentStreamNotWritableException();
		}

		$this->body?->append($string);
		return strlen($string);
	}

	/**
	 * Returns whether or not the stream is readable.
	 *
	 * @return bool
	 */
	public function isReadable():bool {
		$mode = $this->getMetadata("mode") ?? "";
		$readable = false;

		if(strstr($mode, "r")
			|| strstr($mode, "+")) {
			$readable = true;
		}

		return $readable;
	}

	public function open():Document {
		if(!$this instanceof HTMLDocument) {
			throw new WriteOnNonHTMLDocumentException();
		}
		/** @var HTMLDocument $this */
		$this->stream = fopen("php://memory", "r+");
		return $this;
	}

	/**
	 * Read data from the stream.
	 *
	 * @param int $length Read up to $length bytes from the object and return
	 *     them. Fewer than $length bytes may be returned if underlying stream
	 *     call returns fewer bytes.
	 * @return string Returns the data read from the stream, or an empty string
	 *     if no bytes are available.
	 * @throws RuntimeException if an error occurs.
	 */
	public function read($length):string {
		$tell = $this->tell();
		$this->fillStream();
		$this->seek($tell);
		return fread($this->stream, $length);
	}

	/**
	 * Returns the remaining contents in a string
	 *
	 * @return string
	 * @throws RuntimeException if unable to read or an error occurs while
	 *     reading.
	 */
	public function getContents():string {
		$this->fillStream();
		return stream_get_contents($this->stream);
	}

	/**
	 * Get stream metadata as an associative array or retrieve a specific key.
	 *
	 * The keys returned are identical to the keys returned from PHP's
	 * stream_get_meta_data() function.
	 *
	 * @link http://php.net/manual/en/function.stream-get-meta-data.php
	 * @param string $key Specific metadata to retrieve.
	 * @return array|mixed|null Returns an associative array if no key is
	 *     provided. Returns a specific key value if a key is provided and the
	 *     value is found, or null if the key is not found.
	 */
	public function getMetadata($key = null):mixed {
		try {
			$metaData = stream_get_meta_data($this->stream);
		}
		catch(TypeError) {
			return null;
		}

		if(is_null($key)) {
			return $metaData;
		}

		return $metaData[$key] ?? null;
	}

	private function fillStream():void {
		if(!isset($this->stream)) {
			throw new DocumentStreamIsClosedException("DocumentStream is closed");
		}

		if(isset($this->streamBytesFilled)) {
			return;
		}

		$this->streamBytesFilled = fwrite($this->stream, $this->__toString());
		fseek($this->stream, 0);
	}
}