Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.
   1  <?php
   2  
   3  declare(strict_types=1);
   4  
   5  namespace GuzzleHttp\Psr7;
   6  
   7  use Psr\Http\Message\StreamInterface;
   8  
   9  /**
  10   * Converts Guzzle streams into PHP stream resources.
  11   *
  12   * @see https://www.php.net/streamwrapper
  13   */
  14  final class StreamWrapper
  15  {
  16      /** @var resource */
  17      public $context;
  18  
  19      /** @var StreamInterface */
  20      private $stream;
  21  
  22      /** @var string r, r+, or w */
  23      private $mode;
  24  
  25      /**
  26       * Returns a resource representing the stream.
  27       *
  28       * @param StreamInterface $stream The stream to get a resource for
  29       *
  30       * @return resource
  31       *
  32       * @throws \InvalidArgumentException if stream is not readable or writable
  33       */
  34      public static function getResource(StreamInterface $stream)
  35      {
  36          self::register();
  37  
  38          if ($stream->isReadable()) {
  39              $mode = $stream->isWritable() ? 'r+' : 'r';
  40          } elseif ($stream->isWritable()) {
  41              $mode = 'w';
  42          } else {
  43              throw new \InvalidArgumentException('The stream must be readable, '
  44                  . 'writable, or both.');
  45          }
  46  
  47          return fopen('guzzle://stream', $mode, false, self::createStreamContext($stream));
  48      }
  49  
  50      /**
  51       * Creates a stream context that can be used to open a stream as a php stream resource.
  52       *
  53       * @return resource
  54       */
  55      public static function createStreamContext(StreamInterface $stream)
  56      {
  57          return stream_context_create([
  58              'guzzle' => ['stream' => $stream]
  59          ]);
  60      }
  61  
  62      /**
  63       * Registers the stream wrapper if needed
  64       */
  65      public static function register(): void
  66      {
  67          if (!in_array('guzzle', stream_get_wrappers())) {
  68              stream_wrapper_register('guzzle', __CLASS__);
  69          }
  70      }
  71  
  72      public function stream_open(string $path, string $mode, int $options, string &$opened_path = null): bool
  73      {
  74          $options = stream_context_get_options($this->context);
  75  
  76          if (!isset($options['guzzle']['stream'])) {
  77              return false;
  78          }
  79  
  80          $this->mode = $mode;
  81          $this->stream = $options['guzzle']['stream'];
  82  
  83          return true;
  84      }
  85  
  86      public function stream_read(int $count): string
  87      {
  88          return $this->stream->read($count);
  89      }
  90  
  91      public function stream_write(string $data): int
  92      {
  93          return $this->stream->write($data);
  94      }
  95  
  96      public function stream_tell(): int
  97      {
  98          return $this->stream->tell();
  99      }
 100  
 101      public function stream_eof(): bool
 102      {
 103          return $this->stream->eof();
 104      }
 105  
 106      public function stream_seek(int $offset, int $whence): bool
 107      {
 108          $this->stream->seek($offset, $whence);
 109  
 110          return true;
 111      }
 112  
 113      /**
 114       * @return resource|false
 115       */
 116      public function stream_cast(int $cast_as)
 117      {
 118          $stream = clone($this->stream);
 119          $resource = $stream->detach();
 120  
 121          return $resource ?? false;
 122      }
 123  
 124      /**
 125       * @return array<int|string, int>
 126       */
 127      public function stream_stat(): array
 128      {
 129          static $modeMap = [
 130              'r'  => 33060,
 131              'rb' => 33060,
 132              'r+' => 33206,
 133              'w'  => 33188,
 134              'wb' => 33188
 135          ];
 136  
 137          return [
 138              'dev'     => 0,
 139              'ino'     => 0,
 140              'mode'    => $modeMap[$this->mode],
 141              'nlink'   => 0,
 142              'uid'     => 0,
 143              'gid'     => 0,
 144              'rdev'    => 0,
 145              'size'    => $this->stream->getSize() ?: 0,
 146              'atime'   => 0,
 147              'mtime'   => 0,
 148              'ctime'   => 0,
 149              'blksize' => 0,
 150              'blocks'  => 0
 151          ];
 152      }
 153  
 154      /**
 155       * @return array<int|string, int>
 156       */
 157      public function url_stat(string $path, int $flags): array
 158      {
 159          return [
 160              'dev'     => 0,
 161              'ino'     => 0,
 162              'mode'    => 0,
 163              'nlink'   => 0,
 164              'uid'     => 0,
 165              'gid'     => 0,
 166              'rdev'    => 0,
 167              'size'    => 0,
 168              'atime'   => 0,
 169              'mtime'   => 0,
 170              'ctime'   => 0,
 171              'blksize' => 0,
 172              'blocks'  => 0
 173          ];
 174      }
 175  }