How to pass options to stream_open in google cloud PHP stream wrapper

299 Views Asked by At

I'm trying to serve large audio files from google cloud storage with seeking support.

I have difficulties understanding php fopen and google stream wrapper working together. When fopen is called it immediately calls stream_open from google StreamWrapper class. However im unable to pass options to it through fopen context. I would like to set bitwise option 0b10000 as its STREAM_MUST_SEEK option. $flags parameter is always 0.

https://www.php.net/manual/en/streamwrapper.stream-open

Documentation shows there are atleast two options you can set, but it doesnt tell where you can set them.

Without $flag set to 0b10000 im getting:

PHP Warning:  stream_copy_to_stream(): Failed to seek to position 85721088 in the stream in /home/project/src/Classes/StreamResponse.php on line 296

If i set $flags to 0b10000 it works and supports seeking.

$opts = array(
  'gs' => array('key' => 'value')
);

$context = stream_context_create($opts);


$out = fopen('php://output', 'wb');
$file = fopen($this->file->getPathname(), 'rb', false, $context);

stream_copy_to_stream($file, $out, $this->maxlen, $this->offset);

fclose($out);
fclose($file);

/**
 * Callback handler for when a stream is opened. For reads, we need to
 * download the file to see if it can be opened.
 *
 * @param string $path The path of the resource to open
 * @param string $mode The fopen mode. Currently only supports ('r', 'rb', 'rt', 'w', 'wb', 'wt')
 * @param int $flags Bitwise options STREAM_USE_PATH|STREAM_REPORT_ERRORS|STREAM_MUST_SEEK
 * @param string $openedPath Will be set to the path on success if STREAM_USE_PATH option is set
 * @return bool
 */
public function stream_open($path, $mode, $flags, &$openedPath)
{
    $client = $this->openPath($path);

    // strip off 'b' or 't' from the mode
    $mode = rtrim($mode, 'bt');

    $options = [];
    if ($this->context) {
        $contextOptions = stream_context_get_options($this->context);
        if (array_key_exists($this->protocol, $contextOptions)) {
            $options = $contextOptions[$this->protocol] ?: [];
        }
    }

    if ($mode == 'w') {
        $this->stream = new WriteStream(null, $options);
        $this->stream->setUploader(
            $this->bucket->getStreamableUploader(
                $this->stream,
                $options + ['name' => $this->file]
            )
        );
    } elseif ($mode == 'r') {
        try {
            // Lazy read from the source
            $options['restOptions']['stream'] = true;
            $this->stream = new ReadStream(
                $this->bucket->object($this->file)->downloadAsStream($options)
            );

            // Wrap the response in a caching stream to make it seekable
            if (!$this->stream->isSeekable() && ($flags & STREAM_MUST_SEEK)) {
                $this->stream = new CachingStream($this->stream);
            }
        } catch (ServiceException $ex) {
            return $this->returnError($ex->getMessage(), $flags);
        }
    } else {
        return $this->returnError('Unknown stream_open mode.', $flags);
    }

    if ($flags & STREAM_USE_PATH) {
        $openedPath = $path;
    }
    return true;
}
0

There are 0 best solutions below