You are here

class HttpStreamWrapper in Remote Stream Wrapper 8

HTTP(s) stream wrapper.

Hierarchy

Expanded class hierarchy of HttpStreamWrapper

1 file declares its use of HttpStreamWrapper
HttpStreamWrapperTest.php in tests/src/Unit/HttpStreamWrapperTest.php
1 string reference to 'HttpStreamWrapper'
remote_stream_wrapper.services.yml in ./remote_stream_wrapper.services.yml
remote_stream_wrapper.services.yml
2 services use HttpStreamWrapper
stream_wrapper.http in ./remote_stream_wrapper.services.yml
Drupal\remote_stream_wrapper\StreamWrapper\HttpStreamWrapper
stream_wrapper.https in ./remote_stream_wrapper.services.yml
Drupal\remote_stream_wrapper\StreamWrapper\HttpStreamWrapper

File

src/StreamWrapper/HttpStreamWrapper.php, line 11

Namespace

Drupal\remote_stream_wrapper\StreamWrapper
View source
class HttpStreamWrapper implements RemoteStreamWrapperInterface {
  use ReadOnlyPhpStreamWrapperTrait;
  use HttpClientTrait;

  /**
   * The URI of the resource.
   *
   * @var string
   */
  protected $uri;

  /**
   * The response stream.
   *
   * @var \Psr\Http\Message\StreamInterface
   */
  protected $stream;

  /**
   * Optional configuration for HTTP requests.
   *
   * @var array
   */
  protected $config = [];

  /**
   * {@inheritdoc}
   */
  public static function getType() {
    return StreamWrapperInterface::READ & StreamWrapperInterface::HIDDEN;
  }

  /**
   * {@inheritdoc}
   */
  public function getName() {
    return 'HTTP stream wrapper';
  }

  /**
   * {@inheritdoc}
   */
  public function getDescription() {
    return 'HTTP stream wrapper';
  }

  /**
   * {@inheritdoc}
   */
  public function setUri($uri) {
    $this->uri = $uri;
  }

  /**
   * {@inheritdoc}
   */
  public function getUri() {
    return $this->uri;
  }

  /**
   * {@inheritdoc}
   */
  public function getExternalUrl() {
    return $this->uri;
  }

  /**
   * {@inheritdoc}
   */
  public function realpath() {
    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public function dirname($uri = NULL) {
    if (!isset($uri)) {
      $uri = $this->uri;
    }
    list($scheme, $target) = explode('://', $uri, 2);
    $dirname = dirname($target);
    if ($dirname == '.') {
      $dirname = '';
    }
    return $scheme . '://' . $dirname;
  }

  /**
   * {@inheritdoc}
   *
   * @codeCoverageIgnore
   */
  public function stream_close() {

    // Nothing to do when closing an HTTP stream.
  }

  /**
   * {@inheritdoc}
   */
  public function stream_eof() {
    return $this->stream
      ->eof();
  }

  /**
   * {@inheritdoc}
   */
  public function stream_lock($operation) {
    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function stream_open($path, $mode, $options, &$opened_path) {
    if (!in_array($mode, [
      'r',
      'rb',
      'rt',
    ])) {
      if ($options & STREAM_REPORT_ERRORS) {
        trigger_error('stream_open() write modes not supported for HTTP stream wrappers', E_USER_WARNING);
      }
      return FALSE;
    }
    try {
      $this
        ->setUri($path);
      $this
        ->request();
    } catch (\Exception $e) {
      if ($options & STREAM_REPORT_ERRORS) {

        // TODO: Make this testable.
        watchdog_exception('remote_stream_wrapper', $e);
      }
      return FALSE;
    }
    if ($options & STREAM_USE_PATH) {
      $opened_path = $path;
    }
    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function stream_read($count) {
    return $this->stream
      ->read($count);
  }

  /**
   * {@inheritdoc}
   */
  public function stream_seek($offset, $whence = SEEK_SET) {
    try {
      $this->stream
        ->seek($offset, $whence);
    } catch (\RuntimeException $e) {

      // TODO Make this testable.
      watchdog_exception('remote_stream_wrapper', $e);
      return FALSE;
    }
    return TRUE;
  }

  /**
   * Change stream options.
   *
   * This method is called to set options on the stream.
   *
   * @param int $option
   *   One of:
   *   - STREAM_OPTION_BLOCKING: The method was called in response to
   *     stream_set_blocking().
   *   - STREAM_OPTION_READ_TIMEOUT: The method was called in response to
   *     stream_set_timeout().
   *   - STREAM_OPTION_WRITE_BUFFER: The method was called in response to
   *     stream_set_write_buffer().
   * @param int $arg1
   *   If option is:
   *   - STREAM_OPTION_BLOCKING: The requested blocking mode:
   *     - 1 means blocking.
   *     - 0 means not blocking.
   *   - STREAM_OPTION_READ_TIMEOUT: The timeout in seconds.
   *   - STREAM_OPTION_WRITE_BUFFER: The buffer mode, STREAM_BUFFER_NONE or
   *     STREAM_BUFFER_FULL.
   * @param int $arg2
   *   If option is:
   *   - STREAM_OPTION_BLOCKING: This option is not set.
   *   - STREAM_OPTION_READ_TIMEOUT: The timeout in microseconds.
   *   - STREAM_OPTION_WRITE_BUFFER: The requested buffer size.
   *
   * @return bool
   *   TRUE on success, FALSE otherwise. If $option is not implemented, FALSE
   *   should be returned.
   */
  public function stream_set_option($option, $arg1, $arg2) {
    if ($option != STREAM_OPTION_READ_TIMEOUT) {
      return FALSE;
    }
    $this->config['timeout'] = $arg1 + $arg2 / 1000000;
    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function stream_stat() {

    // @see https://github.com/guzzle/psr7/blob/master/src/StreamWrapper.php
    $stat = [
      'dev' => 0,
      // device number
      'ino' => 0,
      // inode number
      'mode' => 0100000 | 0444,
      // inode protection (regular file + read only)
      'nlink' => 0,
      // number of links
      'uid' => 0,
      // userid of owner
      'gid' => 0,
      // groupid of owner
      'rdev' => 0,
      // device type, if inode device *
      'size' => 0,
      // size in bytes
      'atime' => 0,
      // time of last access (Unix timestamp)
      'mtime' => 0,
      // time of last modification (Unix timestamp)
      'ctime' => 0,
      // time of last inode change (Unix timestamp)
      'blksize' => 0,
      // blocksize of filesystem IO
      'blocks' => 0,
    ];
    try {
      $response = $this
        ->requestTryHeadLookingForHeader($this->uri, 'Content-Length', $this->config);
      if ($response
        ->hasHeader('Content-Length')) {
        $stat['size'] = (int) $response
          ->getHeaderLine('Content-Length');
      }
      elseif ($size = $response
        ->getBody()
        ->getSize()) {
        $stat['size'] = $size;
      }
      if ($response
        ->hasHeader('Last-Modified')) {
        if ($mtime = strtotime($response
          ->getHeaderLine('Last-Modified'))) {
          $stat['mtime'] = $mtime;
        }
      }
      return $stat;
    } catch (\Exception $exception) {
      watchdog_exception('remote_stream_wrapper', $exception);
      return NULL;
    }
  }

  /**
   * {@inheritdoc}
   */
  public function stream_tell() {
    return $this->stream
      ->tell();
  }

  /**
   * {@inheritdoc}
   */
  public function url_stat($path, $flags) {
    $this
      ->setUri($path);
    if ($flags & STREAM_URL_STAT_QUIET) {
      return @$this
        ->stream_stat();
    }
    else {
      return $this
        ->stream_stat();
    }
  }

  /**
   * Returns the current HTTP client configuration.
   *
   * @return array
   */
  public function getHttpConfig() {
    return $this->config;
  }

  /**
   * {@inheritdoc}
   */
  public function request($method = 'GET') {
    $response = $this
      ->getHttpClient()
      ->request($method, $this->uri, $this->config);
    if ($method !== 'HEAD') {
      $this->stream = $response
        ->getBody();
    }
    return $response;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
HttpClientTrait::$httpClient protected property The HTTP client.
HttpClientTrait::getHttpClient public function Returns the HTTP client.
HttpClientTrait::requestTryHeadLookingForHeader public function Perform a HEAD/GET request looking for a specific header.
HttpClientTrait::setHttpClient public function Sets the HTTP client.
HttpStreamWrapper::$config protected property Optional configuration for HTTP requests.
HttpStreamWrapper::$stream protected property The response stream.
HttpStreamWrapper::$uri protected property The URI of the resource.
HttpStreamWrapper::dirname public function Gets the name of the directory from a given path. Overrides StreamWrapperInterface::dirname
HttpStreamWrapper::getDescription public function Returns the description of the stream wrapper for use in the UI. Overrides StreamWrapperInterface::getDescription
HttpStreamWrapper::getExternalUrl public function Returns a web accessible URL for the resource. Overrides StreamWrapperInterface::getExternalUrl
HttpStreamWrapper::getHttpConfig public function Returns the current HTTP client configuration.
HttpStreamWrapper::getName public function Returns the name of the stream wrapper for use in the UI. Overrides StreamWrapperInterface::getName
HttpStreamWrapper::getType public static function Returns the type of stream wrapper. Overrides StreamWrapperInterface::getType
HttpStreamWrapper::getUri public function Returns the stream resource URI. Overrides StreamWrapperInterface::getUri
HttpStreamWrapper::realpath public function Returns canonical, absolute path of the resource. Overrides StreamWrapperInterface::realpath
HttpStreamWrapper::request public function Perform an HTTP request for the current URI. Overrides RemoteStreamWrapperInterface::request
HttpStreamWrapper::setUri public function Sets the absolute stream resource URI. Overrides StreamWrapperInterface::setUri
HttpStreamWrapper::stream_close public function @codeCoverageIgnore Overrides PhpStreamWrapperInterface::stream_close
HttpStreamWrapper::stream_eof public function Overrides PhpStreamWrapperInterface::stream_eof
HttpStreamWrapper::stream_lock public function Overrides PhpStreamWrapperInterface::stream_lock
HttpStreamWrapper::stream_open public function Overrides PhpStreamWrapperInterface::stream_open
HttpStreamWrapper::stream_read public function Overrides PhpStreamWrapperInterface::stream_read
HttpStreamWrapper::stream_seek public function Seeks to specific location in a stream. Overrides PhpStreamWrapperInterface::stream_seek
HttpStreamWrapper::stream_set_option public function Change stream options. Overrides PhpStreamWrapperInterface::stream_set_option
HttpStreamWrapper::stream_stat public function Overrides PhpStreamWrapperInterface::stream_stat
HttpStreamWrapper::stream_tell public function Overrides PhpStreamWrapperInterface::stream_tell
HttpStreamWrapper::url_stat public function Overrides PhpStreamWrapperInterface::url_stat
ReadOnlyPhpStreamWrapperTrait::dir_closedir public function
ReadOnlyPhpStreamWrapperTrait::dir_opendir public function
ReadOnlyPhpStreamWrapperTrait::dir_readdir public function
ReadOnlyPhpStreamWrapperTrait::dir_rewinddir public function
ReadOnlyPhpStreamWrapperTrait::mkdir public function
ReadOnlyPhpStreamWrapperTrait::rename public function
ReadOnlyPhpStreamWrapperTrait::rmdir public function
ReadOnlyPhpStreamWrapperTrait::stream_cast public function
ReadOnlyPhpStreamWrapperTrait::stream_flush public function Support for fflush().
ReadOnlyPhpStreamWrapperTrait::stream_metadata public function
ReadOnlyPhpStreamWrapperTrait::stream_truncate public function
ReadOnlyPhpStreamWrapperTrait::stream_write public function
ReadOnlyPhpStreamWrapperTrait::unlink public function Support for unlink().
RemoteStreamWrapperInterface::REMOTE constant Refers to a remote file system location.
RemoteStreamWrapperInterface::REMOTE_NORMAL constant Visible and readable using remote files.
StreamWrapperInterface::ALL constant A filter that matches all wrappers.
StreamWrapperInterface::HIDDEN constant Defines the stream wrapper bit flag for a hidden file.
StreamWrapperInterface::LOCAL constant Refers to a local file system location.
StreamWrapperInterface::LOCAL_HIDDEN constant Hidden, readable and writable using local files.
StreamWrapperInterface::LOCAL_NORMAL constant Visible, readable and writable using local files.
StreamWrapperInterface::NORMAL constant This is the default 'type' flag. This does not include StreamWrapperInterface::LOCAL, because PHP grants a greater trust level to local files (for example, they can be used in an "include" statement, regardless of the…
StreamWrapperInterface::READ constant Wrapper is readable (almost always true).
StreamWrapperInterface::READ_VISIBLE constant Visible and read-only.
StreamWrapperInterface::VISIBLE constant Exposed in the UI and potentially web accessible.
StreamWrapperInterface::WRITE constant Wrapper is writable.
StreamWrapperInterface::WRITE_VISIBLE constant Visible, readable and writable.