[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/php-ai-client/third-party/Nyholm/Psr7/ -> Stream.php (source)

   1  <?php
   2  
   3  declare (strict_types=1);
   4  namespace WordPress\AiClientDependencies\Nyholm\Psr7;
   5  
   6  use WordPress\AiClientDependencies\Psr\Http\Message\StreamInterface;
   7  /**
   8   * @author Michael Dowling and contributors to guzzlehttp/psr7
   9   * @author Tobias Nyholm <tobias.nyholm@gmail.com>
  10   * @author Martijn van der Ven <martijn@vanderven.se>
  11   *
  12   * @final This class should never be extended. See https://github.com/Nyholm/psr7/blob/master/doc/final.md
  13   */
  14  class Stream implements StreamInterface
  15  {
  16      use StreamTrait;
  17      /** @var resource|null A resource reference */
  18      private $stream;
  19      /** @var bool */
  20      private $seekable;
  21      /** @var bool */
  22      private $readable;
  23      /** @var bool */
  24      private $writable;
  25      /** @var array|mixed|void|bool|null */
  26      private $uri;
  27      /** @var int|null */
  28      private $size;
  29      /** @var array Hash of readable and writable stream types */
  30      private const READ_WRITE_HASH = ['read' => ['r' => \true, 'w+' => \true, 'r+' => \true, 'x+' => \true, 'c+' => \true, 'rb' => \true, 'w+b' => \true, 'r+b' => \true, 'x+b' => \true, 'c+b' => \true, 'rt' => \true, 'w+t' => \true, 'r+t' => \true, 'x+t' => \true, 'c+t' => \true, 'a+' => \true], 'write' => ['w' => \true, 'w+' => \true, 'rw' => \true, 'r+' => \true, 'x+' => \true, 'c+' => \true, 'wb' => \true, 'w+b' => \true, 'r+b' => \true, 'x+b' => \true, 'c+b' => \true, 'w+t' => \true, 'r+t' => \true, 'x+t' => \true, 'c+t' => \true, 'a' => \true, 'a+' => \true]];
  31      /**
  32       * @param resource $body
  33       */
  34      public function __construct($body)
  35      {
  36          if (!\is_resource($body)) {
  37              throw new \InvalidArgumentException('First argument to Stream::__construct() must be resource');
  38          }
  39          $this->stream = $body;
  40          $meta = \stream_get_meta_data($this->stream);
  41          $this->seekable = $meta['seekable'] && 0 === \fseek($this->stream, 0, \SEEK_CUR);
  42          $this->readable = isset(self::READ_WRITE_HASH['read'][$meta['mode']]);
  43          $this->writable = isset(self::READ_WRITE_HASH['write'][$meta['mode']]);
  44      }
  45      /**
  46       * Creates a new PSR-7 stream.
  47       *
  48       * @param string|resource|StreamInterface $body
  49       *
  50       * @throws \InvalidArgumentException
  51       */
  52      public static function create($body = ''): StreamInterface
  53      {
  54          if ($body instanceof StreamInterface) {
  55              return $body;
  56          }
  57          if (\is_string($body)) {
  58              if (200000 <= \strlen($body)) {
  59                  $body = self::openZvalStream($body);
  60              } else {
  61                  $resource = \fopen('php://memory', 'r+');
  62                  \fwrite($resource, $body);
  63                  \fseek($resource, 0);
  64                  $body = $resource;
  65              }
  66          }
  67          if (!\is_resource($body)) {
  68              throw new \InvalidArgumentException('First argument to Stream::create() must be a string, resource or StreamInterface');
  69          }
  70          return new self($body);
  71      }
  72      /**
  73       * Closes the stream when the destructed.
  74       */
  75      public function __destruct()
  76      {
  77          $this->close();
  78      }
  79      public function close(): void
  80      {
  81          if (isset($this->stream)) {
  82              if (\is_resource($this->stream)) {
  83                  \fclose($this->stream);
  84              }
  85              $this->detach();
  86          }
  87      }
  88      public function detach()
  89      {
  90          if (!isset($this->stream)) {
  91              return null;
  92          }
  93          $result = $this->stream;
  94          unset($this->stream);
  95          $this->size = $this->uri = null;
  96          $this->readable = $this->writable = $this->seekable = \false;
  97          return $result;
  98      }
  99      private function getUri()
 100      {
 101          if (\false !== $this->uri) {
 102              $this->uri = $this->getMetadata('uri') ?? \false;
 103          }
 104          return $this->uri;
 105      }
 106      public function getSize(): ?int
 107      {
 108          if (null !== $this->size) {
 109              return $this->size;
 110          }
 111          if (!isset($this->stream)) {
 112              return null;
 113          }
 114          // Clear the stat cache if the stream has a URI
 115          if ($uri = $this->getUri()) {
 116              \clearstatcache(\true, $uri);
 117          }
 118          $stats = \fstat($this->stream);
 119          if (isset($stats['size'])) {
 120              $this->size = $stats['size'];
 121              return $this->size;
 122          }
 123          return null;
 124      }
 125      public function tell(): int
 126      {
 127          if (!isset($this->stream)) {
 128              throw new \RuntimeException('Stream is detached');
 129          }
 130          if (\false === $result = @\ftell($this->stream)) {
 131              throw new \RuntimeException('Unable to determine stream position: ' . (\error_get_last()['message'] ?? ''));
 132          }
 133          return $result;
 134      }
 135      public function eof(): bool
 136      {
 137          return !isset($this->stream) || \feof($this->stream);
 138      }
 139      public function isSeekable(): bool
 140      {
 141          return $this->seekable;
 142      }
 143      public function seek($offset, $whence = \SEEK_SET): void
 144      {
 145          if (!isset($this->stream)) {
 146              throw new \RuntimeException('Stream is detached');
 147          }
 148          if (!$this->seekable) {
 149              throw new \RuntimeException('Stream is not seekable');
 150          }
 151          if (-1 === \fseek($this->stream, $offset, $whence)) {
 152              throw new \RuntimeException('Unable to seek to stream position "' . $offset . '" with whence ' . \var_export($whence, \true));
 153          }
 154      }
 155      public function rewind(): void
 156      {
 157          $this->seek(0);
 158      }
 159      public function isWritable(): bool
 160      {
 161          return $this->writable;
 162      }
 163      public function write($string): int
 164      {
 165          if (!isset($this->stream)) {
 166              throw new \RuntimeException('Stream is detached');
 167          }
 168          if (!$this->writable) {
 169              throw new \RuntimeException('Cannot write to a non-writable stream');
 170          }
 171          // We can't know the size after writing anything
 172          $this->size = null;
 173          if (\false === $result = @\fwrite($this->stream, $string)) {
 174              throw new \RuntimeException('Unable to write to stream: ' . (\error_get_last()['message'] ?? ''));
 175          }
 176          return $result;
 177      }
 178      public function isReadable(): bool
 179      {
 180          return $this->readable;
 181      }
 182      public function read($length): string
 183      {
 184          if (!isset($this->stream)) {
 185              throw new \RuntimeException('Stream is detached');
 186          }
 187          if (!$this->readable) {
 188              throw new \RuntimeException('Cannot read from non-readable stream');
 189          }
 190          if (\false === $result = @\fread($this->stream, $length)) {
 191              throw new \RuntimeException('Unable to read from stream: ' . (\error_get_last()['message'] ?? ''));
 192          }
 193          return $result;
 194      }
 195      public function getContents(): string
 196      {
 197          if (!isset($this->stream)) {
 198              throw new \RuntimeException('Stream is detached');
 199          }
 200          $exception = null;
 201          \set_error_handler(static function ($type, $message) use (&$exception) {
 202              throw $exception = new \RuntimeException('Unable to read stream contents: ' . $message);
 203          });
 204          try {
 205              return \stream_get_contents($this->stream);
 206          } catch (\Throwable $e) {
 207              throw $e === $exception ? $e : new \RuntimeException('Unable to read stream contents: ' . $e->getMessage(), 0, $e);
 208          } finally {
 209              \restore_error_handler();
 210          }
 211      }
 212      /**
 213       * @return mixed
 214       */
 215      public function getMetadata($key = null)
 216      {
 217          if (null !== $key && !\is_string($key)) {
 218              throw new \InvalidArgumentException('Metadata key must be a string');
 219          }
 220          if (!isset($this->stream)) {
 221              return $key ? null : [];
 222          }
 223          $meta = \stream_get_meta_data($this->stream);
 224          if (null === $key) {
 225              return $meta;
 226          }
 227          return $meta[$key] ?? null;
 228      }
 229      private static function openZvalStream(string $body)
 230      {
 231          static $wrapper;
 232          $wrapper ?? \stream_wrapper_register('Nyholm-Psr7-Zval', $wrapper = \get_class(new class
 233          {
 234              public $context;
 235              private $data;
 236              private $position = 0;
 237              public function stream_open(): bool
 238              {
 239                  $this->data = \stream_context_get_options($this->context)['Nyholm-Psr7-Zval']['data'];
 240                  \stream_context_set_option($this->context, 'Nyholm-Psr7-Zval', 'data', null);
 241                  return \true;
 242              }
 243              public function stream_read(int $count): string
 244              {
 245                  $result = \substr($this->data, $this->position, $count);
 246                  $this->position += \strlen($result);
 247                  return $result;
 248              }
 249              public function stream_write(string $data): int
 250              {
 251                  $this->data = \substr_replace($this->data, $data, $this->position, \strlen($data));
 252                  $this->position += \strlen($data);
 253                  return \strlen($data);
 254              }
 255              public function stream_tell(): int
 256              {
 257                  return $this->position;
 258              }
 259              public function stream_eof(): bool
 260              {
 261                  return \strlen($this->data) <= $this->position;
 262              }
 263              public function stream_stat(): array
 264              {
 265                  return [
 266                      'mode' => 33206,
 267                      // POSIX_S_IFREG | 0666
 268                      'nlink' => 1,
 269                      'rdev' => -1,
 270                      'size' => \strlen($this->data),
 271                      'blksize' => -1,
 272                      'blocks' => -1,
 273                  ];
 274              }
 275              public function stream_seek(int $offset, int $whence): bool
 276              {
 277                  if (\SEEK_SET === $whence && (0 <= $offset && \strlen($this->data) >= $offset)) {
 278                      $this->position = $offset;
 279                  } elseif (\SEEK_CUR === $whence && 0 <= $offset) {
 280                      $this->position += $offset;
 281                  } elseif (\SEEK_END === $whence && (0 > $offset && 0 <= $offset = \strlen($this->data) + $offset)) {
 282                      $this->position = $offset;
 283                  } else {
 284                      return \false;
 285                  }
 286                  return \true;
 287              }
 288              public function stream_set_option(): bool
 289              {
 290                  return \true;
 291              }
 292              public function stream_truncate(int $new_size): bool
 293              {
 294                  if ($new_size) {
 295                      $this->data = \substr($this->data, 0, $new_size);
 296                      $this->position = \min($this->position, $new_size);
 297                  } else {
 298                      $this->data = '';
 299                      $this->position = 0;
 300                  }
 301                  return \true;
 302              }
 303          }));
 304          $context = \stream_context_create(['Nyholm-Psr7-Zval' => ['data' => $body]]);
 305          if (!$stream = @\fopen('Nyholm-Psr7-Zval://', 'r+', \false, $context)) {
 306              \stream_wrapper_register('Nyholm-Psr7-Zval', $wrapper);
 307              $stream = \fopen('Nyholm-Psr7-Zval://', 'r+', \false, $context);
 308          }
 309          return $stream;
 310      }
 311  }


Generated : Sat Jun 13 09:38:55 2026 Cross-referenced by PHPXref