Browse Source

Fix #18290: Fix response with non-seekable streams

tags/2.0.39
Tobias Munk 4 years ago committed by GitHub
parent
commit
88e79d3f8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      Dockerfile
  2. 1
      framework/CHANGELOG.md
  3. 25
      framework/web/Response.php
  4. 14
      tests/framework/web/ResponseTest.php

4
Dockerfile

@ -4,6 +4,10 @@ FROM ${DOCKER_YII2_PHP_IMAGE}
# Project source-code # Project source-code
WORKDIR /project WORKDIR /project
ADD composer.* /project/ ADD composer.* /project/
# Apply testing patches
ADD tests/phpunit_mock_objects.patch /project/tests/phpunit_mock_objects.patch
ADD tests/phpunit_getopt.patch /project/tests/phpunit_getopt.patch
# Install packgaes
RUN /usr/local/bin/composer install --prefer-dist RUN /usr/local/bin/composer install --prefer-dist
ADD ./ /project ADD ./ /project
ENV PATH /project/vendor/bin:${PATH} ENV PATH /project/vendor/bin:${PATH}

1
framework/CHANGELOG.md

@ -4,6 +4,7 @@ Yii Framework 2 Change Log
2.0.39 under development 2.0.39 under development
------------------------ ------------------------
- Bug #18290: Fix response with non-seekable streams (schmunk42)
- Bug #16418: Fixed `yii\data\Pagination::getLinks()` to return links to the first and the last pages regardless of the current page (ptz-nerf, bizley) - Bug #16418: Fixed `yii\data\Pagination::getLinks()` to return links to the first and the last pages regardless of the current page (ptz-nerf, bizley)
- Bug #18297: Replace usage of deprecated `ReflectionParameter::isArray()` method in PHP8 (baletskyi) - Bug #18297: Replace usage of deprecated `ReflectionParameter::isArray()` method in PHP8 (baletskyi)
- Bug #18308: Fixed `\yii\base\Model::getErrorSummary()` reverse order (DrDeath72) - Bug #18308: Fixed `\yii\base\Model::getErrorSummary()` reverse order (DrDeath72)

25
framework/web/Response.php

@ -441,7 +441,12 @@ class Response extends \yii\base\Response
if (is_array($this->stream)) { if (is_array($this->stream)) {
list($handle, $begin, $end) = $this->stream; list($handle, $begin, $end) = $this->stream;
// only seek if stream is seekable
if ($this->isSeekable($handle)) {
fseek($handle, $begin); fseek($handle, $begin);
}
while (!feof($handle) && ($pos = ftell($handle)) <= $end) { while (!feof($handle) && ($pos = ftell($handle)) <= $end) {
if ($pos + $chunkSize > $end) { if ($pos + $chunkSize > $end) {
$chunkSize = $end - $pos + 1; $chunkSize = $end - $pos + 1;
@ -583,8 +588,12 @@ class Response extends \yii\base\Response
if (isset($options['fileSize'])) { if (isset($options['fileSize'])) {
$fileSize = $options['fileSize']; $fileSize = $options['fileSize'];
} else { } else {
if ($this->isSeekable($handle)) {
fseek($handle, 0, SEEK_END); fseek($handle, 0, SEEK_END);
$fileSize = ftell($handle); $fileSize = ftell($handle);
} else {
$fileSize = 0;
}
} }
$range = $this->getHttpRange($fileSize); $range = $this->getHttpRange($fileSize);
@ -1089,4 +1098,20 @@ class Response extends \yii\base\Response
} }
} }
} }
/**
* Checks if a stream is seekable
*
* @param $handle
* @return bool
*/
private function isSeekable($handle)
{
if (!is_resource($handle)) {
return true;
}
$metaData = stream_get_meta_data($handle);
return isset($metaData['seekable']) && $metaData['seekable'] === true;
}
} }

14
tests/framework/web/ResponseTest.php

@ -191,6 +191,20 @@ class ResponseTest extends \yiiunit\TestCase
$this->assertEquals($statusCode, $this->response->getStatusCode()); $this->assertEquals($statusCode, $this->response->getStatusCode());
} }
/**
* @see https://github.com/yiisoft/yii2/pull/18290
*/
public function testNonSeekableStream()
{
$stream = fopen('php://output', 'r+');
ob_start();
$this->response
->sendStreamAsFile($stream, 'test-stream')
->send();
ob_get_clean();
static::assertEquals(200, $this->response->statusCode);
}
public function dataProviderSetStatusCodeByException() public function dataProviderSetStatusCodeByException()
{ {
$data = [ $data = [

Loading…
Cancel
Save