bkdotcom/PHPDebugConsole

View on GitHub
src/HttpMessage/AbstractStream.php

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
<?php

/**
 * This file is part of HttpMessage
 *
 * @package   bdk/http-message
 * @author    Brad Kent <bkfake-github@yahoo.com>
 * @license   http://opensource.org/licenses/MIT MIT
 * @copyright 2014-2024 Brad Kent
 * @version   v1.0
 */

namespace bdk\HttpMessage;

use InvalidArgumentException;
use RuntimeException;

/**
 * Extended by Stream
 */
abstract class AbstractStream
{
    /** @var array<string, string> */
    protected $strings = array(
        'detached' => 'Stream is detached',
        'fopenFail' => 'The file %s cannot be opened.',
        'posUnknown' => 'Unable to determine stream position',
        'readFail' => 'Unable to read from stream',
        'readFailNonReadable' => 'Unable to read from non-readable stream',
        'readLengthNegative' => 'Length parameter cannot be negative',
        'resourceInvalidType' => 'Expected resource, filename, or string. %s provided.',
        'seekFail' => 'Unable to seek to stream position %s with whence %s',
        'seekNonSeekable' => 'Stream is not seekable',
        'writeFail' => 'Unable to write to stream',
        'writeFailNonWritable' => 'Unable to write to a non-writable stream',
    );

    /** @var resource|closed-resource|null A resource reference */
    protected $resource;

    /**
     * Gets the type name of a variable in a way that is suitable for debugging
     *
     * @param mixed $value The value being type checked
     *
     * @return string
     */
    protected static function getDebugType($value)
    {
        return \is_object($value)
            ? \get_class($value)
            : \gettype($value);
    }

    /**
     * Safely test if value is a file
     *
     * @param mixed $value The value to check
     *
     * @return bool
     *
     * @psalm-assert-if-true non-empty-string $value
     */
    protected static function isFile($value)
    {
        return \is_string($value)
            && \preg_match('#(://|[\r\n\x00])#', $value) !== 1
            && \is_file($value);
    }

    /**
     * Is resource open?
     *
     * @return bool
     *
     * @psalm-assert-if-true resource $this->resource
     */
    protected function isResourceOpen()
    {
        return isset($this->resource) && \is_resource($this->resource);
    }

    /**
     * Set resource
     *
     * @param mixed $value Resource, filepath, or string content to wrap.
     *
     * @return void
     *
     * @throws InvalidArgumentException
     * @throws RuntimeException
     */
    protected function setResource($value)
    {
        if ($value === null) {
            $this->resource = \fopen('php://temp', 'wb+');
            return;
        }
        if (\is_resource($value)) {
            $this->resource = $value;
            return;
        }
        if ($this->isFile($value)) {
            $this->setResourceFile($value);
            return;
        }
        if (\is_string($value)) {
            $this->resource = \fopen('php://temp', 'wb+');
            \fwrite($this->resource, $value);
            \rewind($this->resource);
            return;
        }
        throw new InvalidArgumentException(\sprintf(
            $this->strings['resourceInvalidType'],
            $this->getDebugType($value)
        ));
    }

    /**
     * Set resource to the specified file
     *
     * @param string $file filepath
     *
     * @return void
     *
     * @throws RuntimeException
     */
    protected function setResourceFile($file)
    {
        \set_error_handler(static function () {
            return true; // Don't execute PHP internal error handler
        });
        $this->resource = \fopen($file, 'r');
        \restore_error_handler();
        if ($this->resource === false) {
            throw new RuntimeException(\sprintf(
                $this->strings['fopenFail'],
                $file
            ));
        }
    }
}