我正在尝试从谷歌云存储中提供大型音频文件并寻求支持。
我很难理解 php fopen 和 google 流包装器一起工作。当 fopen 被调用时,它会立即从谷歌 StreamWrapper 类中调用 stream_open。但是我无法通过 fopen 上下文向它传递选项。我想将按位选项 0b10000 设置为其 STREAM_MUST_SEEK 选项。$flags 参数始终为 0。
https://www.php.net/manual/en/streamwrapper.stream-open
文档显示您可以设置至少两个选项,但它没有说明您可以在哪里设置它们。
没有 $flag 设置为 0b10000 我得到:
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
如果我将 $flags 设置为 0b10000 它可以工作并支持搜索。
$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;
}